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

feat: Eip1559 params in extradata #11887

Merged
merged 26 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion crates/ethereum/engine-primitives/src/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ impl From<EthBuiltPayload> for ExecutionPayloadEnvelopeV4 {
}

/// Container type for all components required to build a payload.
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct EthPayloadBuilderAttributes {
/// Id of the payload
pub id: PayloadId,
Expand Down
149 changes: 148 additions & 1 deletion crates/optimism/chainspec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ mod op_sepolia;
use alloc::{vec, vec::Vec};
use alloy_chains::Chain;
use alloy_genesis::Genesis;
use alloy_primitives::{Parity, Signature, B256, U256};
use alloy_primitives::{Bytes, Parity, Signature, B256, U256};
pub use base::BASE_MAINNET;
pub use base_sepolia::BASE_SEPOLIA;
use core::fmt::Display;
Expand Down Expand Up @@ -160,6 +160,16 @@ impl OpChainSpecBuilder {
self
}

/// Enable Holocene at genesis
pub fn holocene_activated(mut self) -> Self {
self = self.granite_activated();
self.inner = self.inner.with_fork(
reth_optimism_forks::OptimismHardfork::Holocene,
ForkCondition::Timestamp(0),
);
self
}

/// Build the resulting [`OpChainSpec`].
///
/// # Panics
Expand All @@ -178,6 +188,58 @@ pub struct OpChainSpec {
pub inner: ChainSpec,
}

impl OpChainSpec {
/// Read from parent to determine the base fee for the next block
pub fn next_block_base_fee(&self, parent: &Header, timestamp: u64) -> U256 {
let is_holocene = self.inner.is_fork_active_at_timestamp(
reth_optimism_forks::OptimismHardfork::Holocene,
timestamp,
);
cody-wang-cb marked this conversation as resolved.
Show resolved Hide resolved
// 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 {
match decode_holocene_1559_params(parent.extra_data.clone()) {
Ok((denominator, elasticity)) => {
if elasticity == 0 && denominator == 0 {
return U256::from(
parent
.next_block_base_fee(self.base_fee_params_at_timestamp(timestamp))
.unwrap_or_default(),
);
}
let base_fee_params =
BaseFeeParams::new(denominator as u128, elasticity as u128);
return U256::from(
parent.next_block_base_fee(base_fee_params).unwrap_or_default(),
)
}
Err(e) => {
panic!("Error occurred: {}", e)
}
cody-wang-cb marked this conversation as resolved.
Show resolved Hide resolved
}
} else {
U256::from(
parent
.next_block_base_fee(self.base_fee_params_at_timestamp(timestamp))
.unwrap_or_default(),
)
}
}
}

/// 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(extra_data: Bytes) -> Result<(u32, u32), String> {
if extra_data.len() < 9 {
return Err("Insufficient data".to_string());
}
let denominator: [u8; 4] =
extra_data[1..5].try_into().map_err(|_| "Failed to extract denominator".to_string())?;
let elasticity: [u8; 4] =
extra_data[5..9].try_into().map_err(|_| "Failed to extract elasticity".to_string())?;
Ok((u32::from_be_bytes(denominator), u32::from_be_bytes(elasticity)))
}
cody-wang-cb marked this conversation as resolved.
Show resolved Hide resolved

/// Returns the signature for the optimism deposit transactions, which don't include a
/// signature.
pub fn optimism_deposit_tx_signature() -> Signature {
Expand Down Expand Up @@ -412,6 +474,8 @@ impl OptimismGenesisInfo {

#[cfg(test)]
mod tests {
use std::sync::Arc;

use alloy_genesis::{ChainConfig, Genesis};
use alloy_primitives::b256;
use reth_chainspec::{test_fork_ids, BaseFeeParams, BaseFeeParamsKind};
Expand Down Expand Up @@ -926,4 +990,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,
extra_data: Bytes::from_static(&[0, 0, 0, 0, 0, 0, 0, 0, 0]),
..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,
extra_data: Bytes::from_static(&[0, 0, 0, 0, 8, 0, 0, 0, 8]),
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()
)
);
}
}
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: &OpChainSpec,
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: &OpChainSpec, 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
8 changes: 1 addition & 7 deletions crates/optimism/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,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,
},
)
}
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,
},
)
}
Expand Down
Loading
Loading