Skip to content
Closed
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
349 changes: 171 additions & 178 deletions Cargo.lock

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions crates/ethereum/engine-primitives/src/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,20 @@ impl PayloadBuilderAttributes for EthPayloadBuilderAttributes {
}
}

impl Default for EthPayloadBuilderAttributes {
fn default() -> Self {
Self {
id: PayloadId::new([0; 8]),
parent: B256::default(),
timestamp: 0,
suggested_fee_recipient: Address::ZERO,
prev_randao: B256::default(),
withdrawals: Withdrawals::default(),
parent_beacon_block_root: None,
}
}
}
Comment on lines +251 to +263
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this can probably be derived

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Requires this change in alloy I think, PTAL
alloy-rs/alloy#1442


/// Generates the payload id for the configured payload from the [`PayloadAttributes`].
///
/// Returns an 8-byte identifier by hashing the payload components with sha256 hash.
Expand Down
133 changes: 130 additions & 3 deletions crates/optimism/chainspec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ mod op_sepolia;
use std::fmt::Display;

use alloy_genesis::Genesis;
use alloy_primitives::{Parity, Signature, B256, U256};
use alloy_primitives::{b64, Parity, Signature, B256, B64, U256};
pub use base::BASE_MAINNET;
pub use base_sepolia::BASE_SEPOLIA;
pub use dev::OP_DEV;
Expand All @@ -34,21 +34,62 @@ use reth_chainspec::{
};
use reth_ethereum_forks::{ChainHardforks, EthereumHardfork, ForkCondition};
use reth_network_peers::NodeRecord;
use reth_optimism_forks::OptimismHardfork;
use reth_primitives_traits::Header;

/// These are the masks for the base fee denominator and elasticity in the nonce, post Holocene
const DENOMINATOR_MASK: B64 = b64!("FFFFFFFF00000000");
const ELASTICITY_MASK: B64 = b64!("00000000FFFFFFFF");

/// OP stack chain spec type.
#[derive(Debug, Clone, Deref, Into, Constructor, PartialEq, Eq)]
pub struct OpChainSpec {
/// [`ChainSpec`].
pub inner: ChainSpec,
}

/// Fee trait for OP chain specs.
pub trait Fee {
/// Read from parent to determine the base fee for the next block
fn next_block_base_fee(&self, parent: &Header, timestamp: u64) -> U256;
}

/// Returns the signature for the optimism deposit transactions, which don't include a
/// signature.
pub fn optimism_deposit_tx_signature() -> Signature {
Signature::new(U256::ZERO, U256::ZERO, Parity::Parity(false))
}

/// Extracts the Holcene 1599 parameters from the encoded form:
/// <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#eip1559params-encoding>
pub fn decode_holocene_1559_params(nonce: B64) -> (u64, u64) {
let elasticity = nonce & ELASTICITY_MASK;
let denominator = nonce & DENOMINATOR_MASK;
(elasticity.into(), denominator.into())
}

impl Fee for OpChainSpec {
fn next_block_base_fee(&self, parent: &Header, timestamp: u64) -> U256 {
Comment thread
clabby marked this conversation as resolved.
let is_holocene =
self.inner.is_fork_active_at_timestamp(OptimismHardfork::Holocene, timestamp);
// If we are in the Holocene, we need to use the base fee params from the parent block's
// nonce Else, use the base fee params from chainspec
if is_holocene && parent.nonce != B64::ZERO {
// First 4 bytes of the nonce are the base fee denominator, the last 4 bytes are the
// elasticity
let (elasticity, denominator) = decode_holocene_1559_params(parent.nonce);
let base_fee_params = BaseFeeParams::new(denominator as u128, elasticity as u128);
U256::from(parent.next_block_base_fee(base_fee_params).unwrap_or_default())
} else {
U256::from(
parent
.next_block_base_fee(self.base_fee_params_at_timestamp(timestamp))
.unwrap_or_default(),
)
}
}
}

impl EthChainSpec for OpChainSpec {
fn chain(&self) -> alloy_chains::Chain {
self.inner.chain()
Expand Down Expand Up @@ -272,11 +313,14 @@ impl OptimismGenesisInfo {

#[cfg(test)]
mod tests {
use crate::OpChainSpec;
use alloc::sync::Arc;
use alloy_genesis::{ChainConfig, Genesis};
use alloy_primitives::b256;
use reth_chainspec::{test_fork_ids, BaseFeeParams, BaseFeeParamsKind};
use alloy_primitives::{b256, U256};
use reth_chainspec::{test_fork_ids, BaseFeeParams, BaseFeeParamsKind, ChainSpec};
use reth_ethereum_forks::{EthereumHardfork, ForkCondition, ForkHash, ForkId, Head};
use reth_optimism_forks::{OptimismHardfork, OptimismHardforks};
use std::str::FromStr;

use crate::*;

Expand Down Expand Up @@ -770,4 +814,87 @@ mod tests {
.all(|(expected, actual)| &**expected == *actual));
assert_eq!(expected_hardforks.len(), hardforks.len());
}

#[test]
fn test_get_base_fee_pre_holocene() {
let op_chain_spec = &BASE_SEPOLIA;
let parent = Header {
base_fee_per_gas: Some(1),
gas_used: 15763614,
gas_limit: 144000000,
..Default::default()
};
let base_fee = op_chain_spec.next_block_base_fee(&parent, 0);
assert_eq!(
base_fee,
U256::from(
parent
.next_block_base_fee(op_chain_spec.base_fee_params_at_timestamp(0))
.unwrap_or_default()
)
);
}

fn holocene_chainspec() -> Arc<OpChainSpec> {
let mut hardforks = OptimismHardfork::base_sepolia();
hardforks.insert(OptimismHardfork::Holocene.boxed(), ForkCondition::Timestamp(1800000000));
Arc::new(OpChainSpec {
inner: ChainSpec {
chain: BASE_SEPOLIA.inner.chain,
genesis: BASE_SEPOLIA.inner.genesis.clone(),
genesis_hash: BASE_SEPOLIA.inner.genesis_hash.clone(),
paris_block_and_final_difficulty: Some((0, U256::from(0))),
hardforks,
base_fee_params: BASE_SEPOLIA.inner.base_fee_params.clone(),
max_gas_limit: crate::constants::BASE_SEPOLIA_MAX_GAS_LIMIT,
prune_delete_limit: 10000,
..Default::default()
},
})
}

#[test]
fn test_get_base_fee_holocene_nonce_not_set() {
let op_chain_spec = holocene_chainspec();
let parent = Header {
base_fee_per_gas: Some(1),
gas_used: 15763614,
gas_limit: 144000000,
timestamp: 1800000003,
..Default::default()
};

let base_fee = op_chain_spec.next_block_base_fee(&parent, 1800000005);
assert_eq!(
base_fee,
U256::from(
parent
.next_block_base_fee(op_chain_spec.base_fee_params_at_timestamp(0))
.unwrap_or_default()
)
);
}

#[test]
fn test_get_base_fee_holocene_nonce_set() {
let op_chain_spec = holocene_chainspec();
let parent = Header {
base_fee_per_gas: Some(1),
gas_used: 15763614,
gas_limit: 144000000,
nonce: B64::from_str("0x0000000800000008").unwrap(),
timestamp: 1800000003,
..Default::default()
};

let base_fee = op_chain_spec.next_block_base_fee(&parent, 1800000005);
assert_eq!(
base_fee,
U256::from(
parent
.next_block_base_fee(BaseFeeParams::new(0x00000008, 0x00000008))
.unwrap_or_default()
)
);
}
}
3 changes: 1 addition & 2 deletions crates/optimism/evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ reth-prune-types.workspace = true

# ethereum
alloy-primitives.workspace = true
alloy-eips.workspace = true
op-alloy-consensus.workspace = true

# Optimism
Expand All @@ -39,8 +40,6 @@ thiserror.workspace = true
tracing.workspace = true

[dev-dependencies]
alloy-eips.workspace = true

reth-revm = { workspace = true, features = ["test-utils"] }
reth-optimism-chainspec.workspace = true
alloy-genesis.workspace = true
Expand Down
8 changes: 6 additions & 2 deletions crates/optimism/evm/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ pub fn revm_spec_by_timestamp_after_bedrock(
chain_spec: &ChainSpec,
timestamp: u64,
) -> revm_primitives::SpecId {
if chain_spec.fork(OptimismHardfork::Granite).active_at_timestamp(timestamp) {
if chain_spec.fork(OptimismHardfork::Holocene).active_at_timestamp(timestamp) {
revm_primitives::HOLOCENE
} else if chain_spec.fork(OptimismHardfork::Granite).active_at_timestamp(timestamp) {
revm_primitives::GRANITE
} else if chain_spec.fork(OptimismHardfork::Fjord).active_at_timestamp(timestamp) {
revm_primitives::FJORD
Expand All @@ -29,7 +31,9 @@ pub fn revm_spec_by_timestamp_after_bedrock(

/// Map the latest active hardfork at the given block to a revm [`SpecId`](revm_primitives::SpecId).
pub fn revm_spec(chain_spec: &ChainSpec, block: &Head) -> revm_primitives::SpecId {
if chain_spec.fork(OptimismHardfork::Granite).active_at_head(block) {
if chain_spec.fork(OptimismHardfork::Holocene).active_at_head(block) {
revm_primitives::HOLOCENE
} else if chain_spec.fork(OptimismHardfork::Granite).active_at_head(block) {
revm_primitives::GRANITE
} else if chain_spec.fork(OptimismHardfork::Fjord).active_at_head(block) {
revm_primitives::FJORD
Expand Down
10 changes: 2 additions & 8 deletions crates/optimism/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

use alloy_primitives::{Address, U256};
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes};
use reth_optimism_chainspec::OpChainSpec;
use reth_optimism_chainspec::{Fee, OpChainSpec};
use reth_primitives::{
revm_primitives::{AnalysisKind, CfgEnvWithHandlerCfg, TxEnv},
transaction::FillTxEnv,
Expand Down Expand Up @@ -160,13 +160,7 @@ impl ConfigureEvmEnv for OptimismEvmConfig {
prevrandao: Some(attributes.prev_randao),
gas_limit: U256::from(parent.gas_limit),
// calculate basefee based on parent block's gas usage
basefee: U256::from(
parent
.next_block_base_fee(
self.chain_spec.base_fee_params_at_timestamp(attributes.timestamp),
)
.unwrap_or_default(),
),
basefee: self.chain_spec.next_block_base_fee(parent, attributes.timestamp),
// calculate excess gas based on parent block's blob gas usage
blob_excess_gas_and_price,
};
Expand Down
4 changes: 4 additions & 0 deletions crates/optimism/hardforks/src/hardfork.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ hardfork!(
Fjord,
/// Granite: <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/superchain-upgrades.md#granite>
Granite,
/// Holocene: <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/superchain-upgrades.md#holocene>
Holocene,
}
);

Expand Down Expand Up @@ -156,6 +158,7 @@ impl OptimismHardfork {
Self::Ecotone => Some(1708534800),
Self::Fjord => Some(1716998400),
Self::Granite => Some(1723478400),
Self::Holocene => None, // TODO: update when Holocene is defined
},
)
}
Expand Down Expand Up @@ -190,6 +193,7 @@ impl OptimismHardfork {
Self::Ecotone => Some(1710374401),
Self::Fjord => Some(1720627201),
Self::Granite => Some(1726070401),
Self::Holocene => None, // TODO: update when Holocene is defined
},
)
}
Expand Down
Loading