Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion Cargo.lock

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

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ morph-primitives = { path = "crates/primitives", default-features = false, featu
morph-revm = { path = "crates/revm", default-features = false }

reth-basic-payload-builder = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
reth-chain-state = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
reth-chainspec = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
reth-cli = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
reth-cli-commands = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
Expand All @@ -72,6 +73,7 @@ reth-ethereum-engine-primitives = { git = "https://github.com/paradigmxyz/reth",
reth-ethereum-primitives = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3", default-features = false }
reth-evm = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
reth-evm-ethereum = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
reth-execution-types = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
reth-metrics = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
reth-network-peers = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
reth-node-api = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
Expand All @@ -81,6 +83,7 @@ reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth", rev = "64909
reth-node-metrics = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
reth-payload-builder = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
reth-payload-primitives = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
reth-payload-util = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
reth-primitives-traits = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3", default-features = false }
reth-provider = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
reth-rpc = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3" }
Expand Down
2 changes: 2 additions & 0 deletions crates/chainspec/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ publish.workspace = true
workspace = true

[dependencies]
morph-primitives.workspace = true

reth-cli = { workspace = true, optional = true }
reth-chainspec.workspace = true
reth-network-peers.workspace = true
Expand Down
9 changes: 7 additions & 2 deletions crates/chainspec/src/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl TryFrom<&OtherFields> for MorphGenesisInfo {
/// the Morph hardforks were activated.
///
/// Note: Bernoulli and Curie use block-based activation, while Morph203, Viridian,
/// and Emerald use timestamp-based activation (matching go-ethereum behavior).
/// Emerald, and MPTFork use timestamp-based activation (matching go-ethereum behavior).
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MorphHardforkInfo {
Expand All @@ -59,6 +59,9 @@ pub struct MorphHardforkInfo {
/// Emerald hardfork timestamp.
#[serde(skip_serializing_if = "Option::is_none")]
pub emerald_time: Option<u64>,
/// MPTFork hardfork timestamp.
#[serde(skip_serializing_if = "Option::is_none")]
pub mpt_fork_time: Option<u64>,
}

impl MorphHardforkInfo {
Expand Down Expand Up @@ -132,7 +135,8 @@ mod tests {
"curieBlock": 100,
"morph203Time": 3000,
"viridianTime": 4000,
"emeraldTime": 5000
"emeraldTime": 5000,
"mptForkTime": 6000
}
"#;

Expand All @@ -147,6 +151,7 @@ mod tests {
morph203_time: Some(3000),
viridian_time: Some(4000),
emerald_time: Some(5000),
mpt_fork_time: Some(6000),
}
);
}
Expand Down
87 changes: 63 additions & 24 deletions crates/chainspec/src/hardfork.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,52 +28,73 @@
//!
//! ## Current State
//!
//! The `Bernoulli` variant is a placeholder representing the pre-hardfork baseline.
//! Bernoulli and Curie use block-based activation, while Morph203, Viridian,
//! Emerald, and MPTFork use timestamp-based activation.

use alloy_evm::revm::primitives::hardfork::SpecId;
use alloy_hardforks::hardfork;
use reth_chainspec::{EthereumHardforks, ForkCondition};

hardfork!(
/// Morph-specific hardforks for network upgrades.
///
/// Note: Bernoulli and Curie use block-based activation, while Morph203, Viridian,
/// Emerald, and MPTFork use timestamp-based activation (matching go-ethereum behavior).
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Default)]
MorphHardfork {
/// Bernoulli.
/// Bernoulli hardfork (block-based).
Bernoulli,
/// Curie hardfork.
/// Curie hardfork (block-based).
Curie,
/// Morph203 hardfork.
/// Morph203 hardfork (timestamp-based).
Morph203,
/// Viridian hardfork.
/// Viridian hardfork (timestamp-based).
Viridian,
/// Emerald hardfork.
#[default]
/// Emerald hardfork (timestamp-based).
Emerald,
/// MPTFork hardfork (timestamp-based).
#[default]
MPTFork,
}
);

impl MorphHardfork {
/// Returns `true` if this hardfork is Bernoulli or later.
#[inline]
pub fn is_bernoulli(self) -> bool {
self >= Self::Bernoulli
}

/// Returns `true` if this hardfork is Curie or later.
#[inline]
pub fn is_curie(self) -> bool {
self >= Self::Curie
}

/// Returns `true` if this hardfork is Morph203 or later.
#[inline]
pub fn is_morph203(self) -> bool {
self >= Self::Morph203
}

/// Returns `true` if this hardfork is Viridian or later.
#[inline]
pub fn is_viridian(self) -> bool {
self >= Self::Viridian
}

/// Returns `true` if this hardfork is Emerald or later.
#[inline]
pub fn is_emerald(self) -> bool {
self >= Self::Emerald
}

/// Returns `true` if this hardfork is MPTFork or later.
#[inline]
pub fn is_mpt_fork(self) -> bool {
self >= Self::MPTFork
}
}

/// Trait for querying Morph-specific hardfork activations.
Expand Down Expand Up @@ -113,12 +134,20 @@ pub trait MorphHardforks: EthereumHardforks {
.active_at_timestamp(timestamp)
}

/// Convenience method to check if MPTFork hardfork is active at a given timestamp.
fn is_mpt_fork_active_at_timestamp(&self, timestamp: u64) -> bool {
self.morph_fork_activation(MorphHardfork::MPTFork)
.active_at_timestamp(timestamp)
}

/// Retrieves the latest Morph hardfork active at a given block and timestamp.
///
/// Note: This method checks both block-based (Bernoulli, Curie) and
/// timestamp-based (Morph203, Viridian, Emerald) hardforks.
/// timestamp-based (Morph203, Viridian, Emerald, MPTFork) hardforks.
fn morph_hardfork_at(&self, block_number: u64, timestamp: u64) -> MorphHardfork {
if self.is_emerald_active_at_timestamp(timestamp) {
if self.is_mpt_fork_active_at_timestamp(timestamp) {
MorphHardfork::MPTFork
} else if self.is_emerald_active_at_timestamp(timestamp) {
MorphHardfork::Emerald
} else if self.is_viridian_active_at_timestamp(timestamp) {
MorphHardfork::Viridian
Expand All @@ -127,6 +156,7 @@ pub trait MorphHardforks: EthereumHardforks {
} else if self.is_curie_active_at_block(block_number) {
MorphHardfork::Curie
} else {
// Default to Bernoulli (baseline)
MorphHardfork::Bernoulli
}
}
Expand All @@ -140,6 +170,7 @@ impl From<MorphHardfork> for SpecId {
MorphHardfork::Morph203 => Self::OSAKA,
MorphHardfork::Viridian => Self::OSAKA,
MorphHardfork::Emerald => Self::OSAKA,
MorphHardfork::MPTFork => Self::OSAKA,
}
}
}
Expand All @@ -151,7 +182,9 @@ impl From<SpecId> for MorphHardfork {
/// `From<MorphHardfork> for SpecId`, because multiple Morph
/// hardforks may share the same underlying EVM spec.
fn from(spec: SpecId) -> Self {
if spec.is_enabled_in(SpecId::from(Self::Emerald)) {
if spec.is_enabled_in(SpecId::from(Self::MPTFork)) {
Self::MPTFork
} else if spec.is_enabled_in(SpecId::from(Self::Emerald)) {
Self::Emerald
} else if spec.is_enabled_in(SpecId::from(Self::Viridian)) {
Self::Viridian
Expand All @@ -171,26 +204,26 @@ mod tests {
use reth_chainspec::Hardfork;

#[test]
fn test_bernoulli_hardfork_name() {
let fork = MorphHardfork::Bernoulli;
assert_eq!(fork.name(), "Bernoulli");
fn test_morph203_hardfork_name() {
let fork = MorphHardfork::Morph203;
assert_eq!(fork.name(), "Morph203");
}

#[test]
fn test_hardfork_trait_implementation() {
let fork = MorphHardfork::Bernoulli;
let fork = MorphHardfork::Morph203;
// Should implement Hardfork trait
let _name: &str = Hardfork::name(&fork);
}

#[test]
#[cfg(feature = "serde")]
fn test_morph_hardfork_serde() {
let fork = MorphHardfork::Bernoulli;
let fork = MorphHardfork::Morph203;

// Serialize to JSON
let json = serde_json::to_string(&fork).unwrap();
assert_eq!(json, "\"Bernoulli\"");
assert_eq!(json, "\"Morph203\"");

// Deserialize from JSON
let deserialized: MorphHardfork = serde_json::from_str(&json).unwrap();
Expand All @@ -204,18 +237,17 @@ mod tests {
assert!(MorphHardfork::Morph203.is_curie());
assert!(MorphHardfork::Viridian.is_curie());
assert!(MorphHardfork::Emerald.is_curie());
assert!(MorphHardfork::MPTFork.is_curie());
}

#[test]
fn test_is_morph203() {
assert!(!MorphHardfork::Bernoulli.is_morph203());
assert!(!MorphHardfork::Curie.is_morph203());

assert!(MorphHardfork::Morph203.is_morph203());
assert!(MorphHardfork::Viridian.is_morph203());
assert!(MorphHardfork::Emerald.is_morph203());

assert!(MorphHardfork::Morph203.is_curie());
assert!(MorphHardfork::MPTFork.is_morph203());
}

#[test]
Expand All @@ -224,9 +256,8 @@ mod tests {
assert!(!MorphHardfork::Curie.is_viridian());
assert!(!MorphHardfork::Morph203.is_viridian());
assert!(MorphHardfork::Viridian.is_viridian());
assert!(MorphHardfork::Viridian.is_morph203());
assert!(MorphHardfork::Viridian.is_curie());
assert!(MorphHardfork::Emerald.is_viridian());
assert!(MorphHardfork::MPTFork.is_viridian());
}

#[test]
Expand All @@ -236,8 +267,16 @@ mod tests {
assert!(!MorphHardfork::Morph203.is_emerald());
assert!(!MorphHardfork::Viridian.is_emerald());
assert!(MorphHardfork::Emerald.is_emerald());
assert!(MorphHardfork::Emerald.is_viridian());
assert!(MorphHardfork::Emerald.is_morph203());
assert!(MorphHardfork::Emerald.is_curie());
assert!(MorphHardfork::MPTFork.is_emerald());
}

#[test]
fn test_is_mpt_fork() {
assert!(!MorphHardfork::Bernoulli.is_mpt_fork());
assert!(!MorphHardfork::Curie.is_mpt_fork());
assert!(!MorphHardfork::Morph203.is_mpt_fork());
assert!(!MorphHardfork::Viridian.is_mpt_fork());
assert!(!MorphHardfork::Emerald.is_mpt_fork());
assert!(MorphHardfork::MPTFork.is_mpt_fork());
}
}
Loading