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
13 changes: 12 additions & 1 deletion 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::U256;
use alloy_primitives::{B64, U256};

use crate::utils::flz_compress_len;
use core::ops::Mul;
Expand Down Expand Up @@ -162,6 +162,17 @@ 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
1 change: 1 addition & 0 deletions crates/rpc-types-engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ op-alloy-protocol.workspace = true

# Alloy
alloy-primitives.workspace = true
alloy-eips.workspace = true
alloy-rpc-types-engine.workspace = true

# Encoding
Expand Down
59 changes: 57 additions & 2 deletions crates/rpc-types-engine/src/attributes.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
//! 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::L2BlockInfo;
use op_alloy_protocol::{fee::decode_eip_1559_params, L2BlockInfo};

/// Optimism Payload Attributes
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct OpPayloadAttributes {
Expand All @@ -33,6 +35,40 @@ pub struct OpPayloadAttributes {
pub eip_1559_params: Option<B64>,
}

impl OpPayloadAttributes {
/// Extracts the `eip1559` parameters for the payload.
pub fn get_holocene_extra_data(
&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))
}
}

/// Optimism Payload Attributes with parent block reference.
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
Expand Down Expand Up @@ -76,6 +112,7 @@ mod test {
use super::*;
use alloy_primitives::{b64, Address, B256};
use alloy_rpc_types_engine::PayloadAttributes;
use core::str::FromStr;

#[test]
fn test_serde_roundtrip_attributes_pre_holocene() {
Expand Down Expand Up @@ -120,4 +157,22 @@ mod test {

assert_eq!(attributes, de);
}

#[test]
fn test_get_extra_data_post_holocene() {
let attributes = OpPayloadAttributes {
eip_1559_params: Some(B64::from_str("0x0000000800000008").unwrap()),
..Default::default()
};
let extra_data = attributes.get_holocene_extra_data(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 attributes =
OpPayloadAttributes { eip_1559_params: Some(B64::ZERO), ..Default::default() };
let extra_data = attributes.get_holocene_extra_data(BaseFeeParams::new(80, 60));
assert_eq!(extra_data.unwrap(), Bytes::copy_from_slice(&[0, 0, 0, 0, 80, 0, 0, 0, 60]));
}
}
28 changes: 28 additions & 0 deletions crates/rpc-types-engine/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//! 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 {}
3 changes: 3 additions & 0 deletions crates/rpc-types-engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ mod superchain;
pub use superchain::{
ProtocolVersion, ProtocolVersionError, ProtocolVersionFormatV0, SuperchainSignal,
};

mod error;
pub use error::EIP1559ParamError;