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
92 changes: 92 additions & 0 deletions crates/consensus/src/eip1559.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//! Support for EIP-1559 parameters after holocene.

use alloy_eips::eip1559::BaseFeeParams;
use alloy_primitives::{Bytes, B64};

/// Extracts the Holocene 1599 parameters from the encoded form:
/// <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#eip1559params-encoding>
///
/// Returns (`elasticity`, `denominator`)
pub fn decode_eip_1559_params(eip_1559_params: B64) -> (u32, u32) {
let denominator: [u8; 4] = eip_1559_params.0[..4].try_into().expect("sufficient length");
let elasticity: [u8; 4] = eip_1559_params.0[4..8].try_into().expect("sufficient length");

(u32::from_be_bytes(elasticity), u32::from_be_bytes(denominator))
}

/// Extracts the `eip1559` parameters for the payload.
pub fn decode_holocene_extra_data(
eip_1559_params: B64,
default_base_fee_params: BaseFeeParams,
) -> Result<Bytes, EIP1559ParamError> {
let mut extra_data = [0u8; 9];
// If eip 1559 params aren't set, use the canyon base fee param constants
// otherwise use them
if eip_1559_params.is_zero() {
// Try casting max_change_denominator to u32
let max_change_denominator: u32 = (default_base_fee_params.max_change_denominator)
.try_into()
.map_err(|_| EIP1559ParamError::DenominatorOverflow)?;

// Try casting elasticity_multiplier to u32
let elasticity_multiplier: u32 = (default_base_fee_params.elasticity_multiplier)
.try_into()
.map_err(|_| EIP1559ParamError::ElasticityOverflow)?;

// Copy the values safely
extra_data[1..5].copy_from_slice(&max_change_denominator.to_be_bytes());
extra_data[5..9].copy_from_slice(&elasticity_multiplier.to_be_bytes());
} else {
let (elasticity, denominator) = decode_eip_1559_params(eip_1559_params);
extra_data[1..5].copy_from_slice(&denominator.to_be_bytes());
extra_data[5..9].copy_from_slice(&elasticity.to_be_bytes());
}
Ok(Bytes::copy_from_slice(&extra_data))
}

/// Error type for EIP-1559 parameters
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EIP1559ParamError {
/// No EIP-1559 parameters provided
NoEIP1559Params,
/// Denominator overflow
DenominatorOverflow,
/// Elasticity overflow
ElasticityOverflow,
}

impl core::fmt::Display for EIP1559ParamError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::NoEIP1559Params => {
write!(f, "No EIP1559 parameters provided")
}
Self::DenominatorOverflow => write!(f, "Denominator overflow"),
Self::ElasticityOverflow => {
write!(f, "Elasticity overflow")
}
}
}
}

impl core::error::Error for EIP1559ParamError {}

#[cfg(test)]
mod tests {
use super::*;
use core::str::FromStr;

#[test]
fn test_get_extra_data_post_holocene() {
let eip_1559_params = B64::from_str("0x0000000800000008").unwrap();
let extra_data = decode_holocene_extra_data(eip_1559_params, BaseFeeParams::new(80, 60));
assert_eq!(extra_data.unwrap(), Bytes::copy_from_slice(&[0, 0, 0, 0, 8, 0, 0, 0, 8]));
}

#[test]
fn test_get_extra_data_post_holocene_default() {
let eip_1559_params = B64::ZERO;
let extra_data = decode_holocene_extra_data(eip_1559_params, BaseFeeParams::new(80, 60));
assert_eq!(extra_data.unwrap(), Bytes::copy_from_slice(&[0, 0, 0, 0, 80, 0, 0, 0, 60]));
}
}
1 change: 1 addition & 0 deletions crates/consensus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub use transaction::{
DEPOSIT_TX_TYPE_ID,
};

pub mod eip1559;
pub mod hardforks;
pub use hardforks::Hardforks;

Expand Down
13 changes: 1 addition & 12 deletions crates/protocol/src/fee.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! This module contains the L1 block fee calculation function.
use alloy_primitives::{B64, U256};
use alloy_primitives::U256;

use crate::utils::flz_compress_len;
use core::ops::Mul;
Expand Down Expand Up @@ -162,17 +162,6 @@ fn calculate_l1_fee_scaled_ecotone(
U256::from(calldata_cost_per_byte).saturating_add(blob_cost_per_byte)
}

/// Extracts the Holocene 1599 parameters from the encoded form:
/// <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#eip1559params-encoding>
///
/// Returns (`elasticity`, `denominator`)
pub fn decode_eip_1559_params(eip_1559_params: B64) -> (u32, u32) {
let denominator: [u8; 4] = eip_1559_params.0[..4].try_into().expect("sufficient length");
let elasticity: [u8; 4] = eip_1559_params.0[4..8].try_into().expect("sufficient length");

(u32::from_be_bytes(elasticity), u32::from_be_bytes(denominator))
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
2 changes: 2 additions & 0 deletions crates/rpc-types-engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ workspace = true

[dependencies]
# Workspace
op-alloy-consensus.workspace = true
op-alloy-protocol.workspace = true

# Alloy
Expand Down Expand Up @@ -48,6 +49,7 @@ std = [
"alloy-rpc-types-engine/ssz",
"alloy-primitives/std",
"alloy-rpc-types-engine/std",
"op-alloy-consensus/std",
"op-alloy-protocol/std",
]
serde = [
Expand Down
34 changes: 7 additions & 27 deletions crates/rpc-types-engine/src/attributes.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
//! Optimism-specific payload attributes.

use crate::error::EIP1559ParamError;
use alloc::vec::Vec;
use alloy_eips::eip1559::BaseFeeParams;
use alloy_primitives::{Bytes, B64};
use alloy_rpc_types_engine::PayloadAttributes;
use op_alloy_protocol::{fee::decode_eip_1559_params, L2BlockInfo};
use op_alloy_consensus::eip1559::{
decode_eip_1559_params, decode_holocene_extra_data, EIP1559ParamError,
};
use op_alloy_protocol::L2BlockInfo;

/// Optimism Payload Attributes
#[derive(Clone, Debug, Default, PartialEq, Eq)]
Expand Down Expand Up @@ -41,31 +43,9 @@ impl OpPayloadAttributes {
&self,
default_base_fee_params: BaseFeeParams,
) -> Result<Bytes, EIP1559ParamError> {
let eip_1559_params = self.eip_1559_params.ok_or(EIP1559ParamError::NoEIP1559Params)?;

let mut extra_data = [0u8; 9];
// If eip 1559 params aren't set, use the canyon base fee param constants
// otherwise use them
if eip_1559_params.is_zero() {
// Try casting max_change_denominator to u32
let max_change_denominator: u32 = (default_base_fee_params.max_change_denominator)
.try_into()
.map_err(|_| EIP1559ParamError::DenominatorOverflow)?;

// Try casting elasticity_multiplier to u32
let elasticity_multiplier: u32 = (default_base_fee_params.elasticity_multiplier)
.try_into()
.map_err(|_| EIP1559ParamError::ElasticityOverflow)?;

// Copy the values safely
extra_data[1..5].copy_from_slice(&max_change_denominator.to_be_bytes());
extra_data[5..9].copy_from_slice(&elasticity_multiplier.to_be_bytes());
} else {
let (elasticity, denominator) = decode_eip_1559_params(eip_1559_params);
extra_data[1..5].copy_from_slice(&denominator.to_be_bytes());
extra_data[5..9].copy_from_slice(&elasticity.to_be_bytes());
}
Ok(Bytes::copy_from_slice(&extra_data))
self.eip_1559_params
.map(|params| decode_holocene_extra_data(params, default_base_fee_params))
.ok_or(EIP1559ParamError::NoEIP1559Params)?
}

/// Extracts the Holocene 1599 parameters from the encoded form:
Expand Down
28 changes: 0 additions & 28 deletions crates/rpc-types-engine/src/error.rs

This file was deleted.

3 changes: 0 additions & 3 deletions crates/rpc-types-engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,3 @@ mod superchain;
pub use superchain::{
ProtocolVersion, ProtocolVersionError, ProtocolVersionFormatV0, SuperchainSignal,
};

mod error;
pub use error::EIP1559ParamError;