Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reth-ethereum-forks crate #5621

Merged
merged 15 commits into from
Dec 1, 2023
243 changes: 166 additions & 77 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ members = [
"crates/consensus/auto-seal/",
"crates/consensus/beacon/",
"crates/consensus/common/",
"crates/ethereum-forks/",
"crates/interfaces/",
"crates/metrics/",
"crates/metrics/metrics-derive/",
Expand Down Expand Up @@ -102,6 +103,7 @@ reth-dns-discovery = { path = "crates/net/dns" }
reth-downloaders = { path = "crates/net/downloaders" }
reth-ecies = { path = "crates/net/ecies" }
reth-eth-wire = { path = "crates/net/eth-wire" }
reth-ethereum-forks = { path = "crates/ethereum-forks" }
reth-interfaces = { path = "crates/interfaces" }
reth-ipc = { path = "crates/rpc/ipc" }
reth-libmdbx = { path = "crates/storage/libmdbx-rs" }
Expand Down
2 changes: 2 additions & 0 deletions bin/reth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ normal = [
# reth
reth-config.workspace = true
reth-primitives = { workspace = true, features = ["arbitrary", "clap"] }
reth-ethereum-forks = { workspace = true }
reth-db = { workspace = true, features = ["mdbx", "test-utils"] }
# TODO: Temporary use of the test-utils feature
reth-provider = { workspace = true, features = ["test-utils"] }
Expand Down Expand Up @@ -120,6 +121,7 @@ min-debug-logs = ["tracing/release_max_level_debug"]
min-trace-logs = ["tracing/release_max_level_trace"]
optimism = [
"reth-primitives/optimism",
"reth-ethereum-forks/optimism",
"reth-revm/optimism",
"reth-interfaces/optimism",
"reth-rpc/optimism",
Expand Down
52 changes: 52 additions & 0 deletions crates/ethereum-forks/Cargo.toml
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs a cleanup, we probably need way less dependencies

mattsse marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[package]
name = "reth-ethereum-forks"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
description = "Ethereum fork types used in reth."

[dependencies]
# reth
reth-codecs.workspace = true
revm-primitives.workspace = true

# ethereum
alloy-primitives = { workspace = true, features = ["rand", "rlp"] }
alloy-rlp = { workspace = true, features = ["arrayvec"] }

# used for forkid
crc = "3"

# misc
clap = { workspace = true, features = ["derive"], optional = true }
serde.workspace = true
thiserror.workspace = true

# `test-utils` feature
plain_hasher = { version = "0.2", optional = true }
hash-db = { version = "~0.15", optional = true }

# arbitrary utils
arbitrary = { workspace = true, features = ["derive"], optional = true }
proptest = { workspace = true, optional = true }
proptest-derive = { workspace = true, optional = true }
strum = { workspace = true, features = ["derive"] }

[dev-dependencies]
rand.workspace = true
revm-primitives = { workspace = true, features = ["arbitrary"] }
arbitrary = { workspace = true, features = ["derive"] }
proptest.workspace = true
proptest-derive.workspace = true

plain_hasher = "0.2"
hash-db = "~0.15"

[features]
arbitrary = ["revm-primitives/arbitrary", "dep:arbitrary", "dep:proptest", "dep:proptest-derive"]
clap = ["dep:clap"]
optimism = ["reth-codecs/optimism", "revm-primitives/optimism"]
test-utils = ["dep:plain_hasher", "dep:hash-db"]
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

#![deny(missing_docs)]

use crate::{hex, BlockNumber, Head, B256};
use crate::Head;
use alloy_primitives::{hex, BlockNumber, B256};
use alloy_rlp::*;
use crc::*;
use reth_codecs::derive_arbitrary;
Expand Down Expand Up @@ -72,10 +73,12 @@ where
}
}

// TODO: Move
/// TODO: Move
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum ForkFilterKey {
/// TODO
Block(BlockNumber),
/// TODO
Time(u64),
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use serde::{Deserialize, Serialize};

use crate::{ChainSpec, ForkCondition, ForkFilter, ForkId};
use std::{fmt::Display, str::FromStr};

/// The name of an Ethereum hardfork.
Expand Down Expand Up @@ -52,25 +51,6 @@ pub enum Hardfork {
Cancun,
}

impl Hardfork {
/// Get the [ForkId] for this hardfork in the given spec, if the fork is activated at any point.
pub fn fork_id(&self, spec: &ChainSpec) -> Option<ForkId> {
match spec.fork(*self) {
ForkCondition::Never => None,
_ => Some(spec.fork_id(&spec.satisfy(spec.fork(*self)))),
}
}

/// Get the [ForkFilter] for this hardfork in the given spec, if the fork is activated at any
/// point.
pub fn fork_filter(&self, spec: &ChainSpec) -> Option<ForkFilter> {
match spec.fork(*self) {
ForkCondition::Never => None,
_ => Some(spec.fork_filter(spec.satisfy(spec.fork(*self)))),
}
}
}

impl FromStr for Hardfork {
type Err = String;

Expand Down Expand Up @@ -115,8 +95,6 @@ impl Display for Hardfork {
#[cfg(test)]
mod tests {
use super::*;
use crate::{Chain, Genesis};
use std::collections::BTreeMap;

#[test]
fn check_hardfork_from_str() {
Expand Down Expand Up @@ -181,34 +159,4 @@ mod tests {
fn check_nonexistent_hardfork_from_str() {
assert!(Hardfork::from_str("not a hardfork").is_err());
}

#[test]
fn check_fork_id_chainspec_with_fork_condition_never() {
let spec = ChainSpec {
chain: Chain::mainnet(),
genesis: Genesis::default(),
genesis_hash: None,
hardforks: BTreeMap::from([(Hardfork::Frontier, ForkCondition::Never)]),
paris_block_and_final_difficulty: None,
deposit_contract: None,
..Default::default()
};

assert_eq!(Hardfork::Frontier.fork_id(&spec), None);
}

#[test]
fn check_fork_filter_chainspec_with_fork_condition_never() {
let spec = ChainSpec {
chain: Chain::mainnet(),
genesis: Genesis::default(),
genesis_hash: None,
hardforks: BTreeMap::from([(Hardfork::Shanghai, ForkCondition::Never)]),
paris_block_and_final_difficulty: None,
deposit_contract: None,
..Default::default()
};

assert_eq!(Hardfork::Shanghai.fork_filter(&spec), None);
}
}
24 changes: 24 additions & 0 deletions crates/ethereum-forks/src/head.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use alloy_primitives::{BlockNumber, B256, U256};
use serde::{Deserialize, Serialize};

/// Describes the current head block.
///
/// The head block is the highest fully synced block.
///
/// Note: This is a slimmed down version of Header, primarily for communicating the highest block
/// with the P2P network and the RPC.
#[derive(
Debug, Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize,
)]
pub struct Head {
/// The number of the head block.
pub number: BlockNumber,
/// The hash of the head block.
pub hash: B256,
/// The difficulty of the head block.
pub difficulty: U256,
/// The total difficulty at the head block.
pub total_difficulty: U256,
/// The timestamp of the head block.
pub timestamp: u64,
}
29 changes: 29 additions & 0 deletions crates/ethereum-forks/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//! Ethereum fork types used in reth.
//!
//! This crate contains Ethereum fork types and helper functions.
//!
//! ## Feature Flags
//!
//! - `arbitrary`: Adds `proptest` and `arbitrary` support for primitive types.
//! - `test-utils`: Export utilities for testing

#![doc(
html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
)]
#![warn(missing_debug_implementations, missing_docs, unreachable_pub, rustdoc::all)]
#![deny(unused_must_use, rust_2018_idioms)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#![allow(clippy::non_canonical_clone_impl)]

mod forkid;
mod hardfork;
mod head;

pub use forkid::{ForkFilter, ForkFilterKey, ForkHash, ForkId, ForkTransition, ValidationError};
pub use hardfork::Hardfork;
pub use head::Head;

#[cfg(any(test, feature = "arbitrary"))]
pub use arbitrary;
2 changes: 1 addition & 1 deletion crates/net/dns/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ mod tests {

let mut builder = EnrBuilder::new("v4");
let mut buf = Vec::new();
let fork_id = Hardfork::Frontier.fork_id(&MAINNET).unwrap();
let fork_id = MAINNET.hardfork_fork_id(Hardfork::Frontier).unwrap();
fork_id.encode(&mut buf);
builder.ip4(Ipv4Addr::LOCALHOST).udp4(30303).tcp4(30303).add_value(b"eth", &buf);
let enr = builder.build(&secret_key).unwrap();
Expand Down
2 changes: 1 addition & 1 deletion crates/net/eth-wire/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use reth_primitives::{Chain, ForkId, B256, U256};
/// total_difficulty: U256::from(100),
/// blockhash: B256::from(MAINNET_GENESIS_HASH),
/// genesis: B256::from(MAINNET_GENESIS_HASH),
/// forkid: Hardfork::Paris.fork_id(&MAINNET).unwrap(),
/// forkid: MAINNET.hardfork_fork_id(Hardfork::Paris).unwrap(),
/// }
/// );
/// ```
Expand Down
4 changes: 2 additions & 2 deletions crates/net/eth-wire/src/types/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ impl Default for Status {
total_difficulty: U256::from(17_179_869_184u64),
blockhash: mainnet_genesis,
genesis: mainnet_genesis,
forkid: Hardfork::Frontier
.fork_id(&MAINNET)
forkid: MAINNET
.hardfork_fork_id(Hardfork::Frontier)
.expect("The Frontier hardfork should always exist"),
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/net/network/src/session/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -926,8 +926,8 @@ mod tests {
secret_key,
local_peer_id,
status: StatusBuilder::default().build(),
fork_filter: Hardfork::Frontier
.fork_filter(&MAINNET)
fork_filter: MAINNET
.hardfork_fork_filter(Hardfork::Frontier)
.expect("The Frontier fork filter should exist on mainnet"),
bandwidth_meter: BandwidthMeter::default(),
}
Expand Down
1 change: 1 addition & 0 deletions crates/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ description = "Commonly used types in reth."
[dependencies]
# reth
reth-codecs.workspace = true
reth-ethereum-forks.workspace = true
reth-rpc-types.workspace = true
revm-primitives.workspace = true
revm.workspace = true
Expand Down
54 changes: 48 additions & 6 deletions crates/primitives/src/chain/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@ use crate::{
EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR, EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
EIP1559_INITIAL_BASE_FEE, EMPTY_RECEIPTS, EMPTY_TRANSACTIONS, EMPTY_WITHDRAWALS,
},
forkid::ForkFilterKey,
header::Head,
proofs::genesis_state_root,
revm_primitives::{address, b256},
Address, BlockNumber, Chain, ForkFilter, ForkHash, ForkId, Genesis, Hardfork, Header,
SealedHeader, B256, EMPTY_OMMER_ROOT_HASH, U256,
Address, BlockNumber, Chain, ForkFilter, ForkFilterKey, ForkHash, ForkId, Genesis, Hardfork,
Head, Header, SealedHeader, B256, EMPTY_OMMER_ROOT_HASH, U256,
};
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -681,19 +679,33 @@ impl ChainSpec {
})
}

/// Get the fork filter for the given hardfork
pub fn hardfork_fork_filter(&self, fork: Hardfork) -> Option<ForkFilter> {
match self.fork(fork) {
ForkCondition::Never => None,
_ => Some(self.fork_filter(self.satisfy(self.fork(fork)))),
}
}

/// Returns the forks in this specification and their activation conditions.
pub fn hardforks(&self) -> &BTreeMap<Hardfork, ForkCondition> {
&self.hardforks
}

/// Get the fork id for the given hardfork.
pub fn hardfork_fork_id(&self, fork: Hardfork) -> Option<ForkId> {
fork.fork_id(self)
match self.fork(fork) {
ForkCondition::Never => None,
_ => Some(self.fork_id(&self.satisfy(self.fork(fork)))),
}
}

/// Convenience method to get the fork id for [Hardfork::Shanghai] from a given chainspec.
pub fn shanghai_fork_id(&self) -> Option<ForkId> {
Hardfork::Shanghai.fork_id(self)
match self.fork(Hardfork::Shanghai) {
ForkCondition::Never => None,
_ => Some(self.fork_id(&self.satisfy(self.fork(Hardfork::Shanghai)))),
}
}

/// Get the fork condition for the given fork.
Expand Down Expand Up @@ -2749,4 +2761,34 @@ Post-merge hard forks (timestamp based):
serde_json::from_str(&serialized_chain_spec).unwrap();
assert!(matches!(deserialized_chain_spec, AllGenesisFormats::Reth(_)))
}

#[test]
fn check_fork_id_chainspec_with_fork_condition_never() {
let spec = ChainSpec {
chain: Chain::mainnet(),
genesis: Genesis::default(),
genesis_hash: None,
hardforks: BTreeMap::from([(Hardfork::Frontier, ForkCondition::Never)]),
paris_block_and_final_difficulty: None,
deposit_contract: None,
..Default::default()
};

assert_eq!(spec.hardfork_fork_id(Hardfork::Frontier), None);
}

#[test]
fn check_fork_filter_chainspec_with_fork_condition_never() {
let spec = ChainSpec {
chain: Chain::mainnet(),
genesis: Genesis::default(),
genesis_hash: None,
hardforks: BTreeMap::from([(Hardfork::Shanghai, ForkCondition::Never)]),
paris_block_and_final_difficulty: None,
deposit_contract: None,
..Default::default()
};

assert_eq!(spec.hardfork_fork_filter(Hardfork::Shanghai), None);
}
}
Loading