diff --git a/crates/consensus/src/eip1559.rs b/crates/consensus/src/eip1559.rs new file mode 100644 index 000000000..fab85704d --- /dev/null +++ b/crates/consensus/src/eip1559.rs @@ -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: +/// +/// +/// 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 { + 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])); + } +} diff --git a/crates/consensus/src/lib.rs b/crates/consensus/src/lib.rs index 5b817e8f7..83a3b4eca 100644 --- a/crates/consensus/src/lib.rs +++ b/crates/consensus/src/lib.rs @@ -19,6 +19,7 @@ pub use transaction::{ DEPOSIT_TX_TYPE_ID, }; +pub mod eip1559; pub mod hardforks; pub use hardforks::Hardforks; diff --git a/crates/protocol/src/fee.rs b/crates/protocol/src/fee.rs index f0aa5ac45..c321e1f90 100644 --- a/crates/protocol/src/fee.rs +++ b/crates/protocol/src/fee.rs @@ -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; @@ -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: -/// -/// -/// 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::*; diff --git a/crates/rpc-types-engine/Cargo.toml b/crates/rpc-types-engine/Cargo.toml index d82e1406d..85dba99eb 100644 --- a/crates/rpc-types-engine/Cargo.toml +++ b/crates/rpc-types-engine/Cargo.toml @@ -16,6 +16,7 @@ workspace = true [dependencies] # Workspace +op-alloy-consensus.workspace = true op-alloy-protocol.workspace = true # Alloy @@ -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 = [ diff --git a/crates/rpc-types-engine/src/attributes.rs b/crates/rpc-types-engine/src/attributes.rs index 4a773053a..ebfe693b2 100644 --- a/crates/rpc-types-engine/src/attributes.rs +++ b/crates/rpc-types-engine/src/attributes.rs @@ -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)] @@ -41,31 +43,9 @@ impl OpPayloadAttributes { &self, default_base_fee_params: BaseFeeParams, ) -> Result { - 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: diff --git a/crates/rpc-types-engine/src/error.rs b/crates/rpc-types-engine/src/error.rs deleted file mode 100644 index 24445d7d5..000000000 --- a/crates/rpc-types-engine/src/error.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! Error types - -/// 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 {} diff --git a/crates/rpc-types-engine/src/lib.rs b/crates/rpc-types-engine/src/lib.rs index 290b40bdb..a116627fe 100644 --- a/crates/rpc-types-engine/src/lib.rs +++ b/crates/rpc-types-engine/src/lib.rs @@ -25,6 +25,3 @@ mod superchain; pub use superchain::{ ProtocolVersion, ProtocolVersionError, ProtocolVersionFormatV0, SuperchainSignal, }; - -mod error; -pub use error::EIP1559ParamError;