From 97ad6dfe1f13e156f128177d2e5bc0d9c121468d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien?= <3535019+leruaa@users.noreply.github.com> Date: Thu, 6 Feb 2025 11:34:31 +0100 Subject: [PATCH] feat: handle Isthmus operator fee params (#14243) --- crates/optimism/evm/src/l1.rs | 87 ++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/crates/optimism/evm/src/l1.rs b/crates/optimism/evm/src/l1.rs index 5e35b34f2..ab09a6e7b 100644 --- a/crates/optimism/evm/src/l1.rs +++ b/crates/optimism/evm/src/l1.rs @@ -27,6 +27,9 @@ const CREATE_2_DEPLOYER_BYTECODE: [u8; 1584] = hex!("608060405260043610610043576 /// The function selector of the "setL1BlockValuesEcotone" function in the `L1Block` contract. const L1_BLOCK_ECOTONE_SELECTOR: [u8; 4] = hex!("440a5e20"); +/// The function selector of the "setL1BlockValuesIsthmus" function in the `L1Block` contract. +const L1_BLOCK_ISTHMUS_SELECTOR: [u8; 4] = hex!("098999be"); + /// Extracts the [`L1BlockInfo`] from the L2 block. The L1 info transaction is always the first /// transaction in the L2 block. /// @@ -69,7 +72,9 @@ pub fn parse_l1_info(input: &[u8]) -> Result // If the first 4 bytes of the calldata are the L1BlockInfoEcotone selector, then we parse the // calldata as an Ecotone hardfork L1BlockInfo transaction. Otherwise, we parse it as a // Bedrock hardfork L1BlockInfo transaction. - if input[0..4] == L1_BLOCK_ECOTONE_SELECTOR { + if input[0..4] == L1_BLOCK_ISTHMUS_SELECTOR { + parse_l1_info_tx_isthmus(input[4..].as_ref()) + } else if input[0..4] == L1_BLOCK_ECOTONE_SELECTOR { parse_l1_info_tx_ecotone(input[4..].as_ref()) } else { parse_l1_info_tx_bedrock(input[4..].as_ref()) @@ -184,6 +189,86 @@ pub fn parse_l1_info_tx_ecotone(data: &[u8]) -> Result Result { + if data.len() != 172 { + return Err(OpBlockExecutionError::L1BlockInfoError { + message: "unexpected l1 block info tx calldata length found".to_string(), + }) + } + + // https://github.com/ethereum-optimism/op-geth/blob/60038121c7571a59875ff9ed7679c48c9f73405d/core/types/rollup_cost.go#L317-L328 + // + // data layout assumed for Ecotone: + // offset type varname + // 0 + // 4 uint32 _basefeeScalar (start offset in this scope) + // 8 uint32 _blobBaseFeeScalar + // 12 uint64 _sequenceNumber, + // 20 uint64 _timestamp, + // 28 uint64 _l1BlockNumber + // 36 uint256 _basefee, + // 68 uint256 _blobBaseFee, + // 100 bytes32 _hash, + // 132 bytes32 _batcherHash, + // 164 uint32 _operatorFeeScalar + // 168 uint64 _operatorFeeConstant + + let l1_base_fee_scalar = U256::try_from_be_slice(&data[..4]).ok_or_else(|| { + OpBlockExecutionError::L1BlockInfoError { + message: "could not convert l1 base fee scalar".to_string(), + } + })?; + let l1_blob_base_fee_scalar = U256::try_from_be_slice(&data[4..8]).ok_or_else(|| { + OpBlockExecutionError::L1BlockInfoError { + message: "could not convert l1 blob base fee scalar".to_string(), + } + })?; + let l1_base_fee = U256::try_from_be_slice(&data[32..64]).ok_or_else(|| { + OpBlockExecutionError::L1BlockInfoError { + message: "could not convert l1 blob base fee".to_string(), + } + })?; + let l1_blob_base_fee = U256::try_from_be_slice(&data[64..96]).ok_or_else(|| { + OpBlockExecutionError::L1BlockInfoError { + message: "could not convert l1 blob base fee".to_string(), + } + })?; + let operator_fee_scalar = U256::try_from_be_slice(&data[160..164]).ok_or_else(|| { + OpBlockExecutionError::L1BlockInfoError { + message: "could not convert operator fee scalar".to_string(), + } + })?; + let operator_fee_constant = U256::try_from_be_slice(&data[164..172]).ok_or_else(|| { + OpBlockExecutionError::L1BlockInfoError { + message: "could not convert operator fee constant".to_string(), + } + })?; + + let mut l1block = L1BlockInfo::default(); + l1block.l1_base_fee = l1_base_fee; + l1block.l1_base_fee_scalar = l1_base_fee_scalar; + l1block.l1_blob_base_fee = Some(l1_blob_base_fee); + l1block.l1_blob_base_fee_scalar = Some(l1_blob_base_fee_scalar); + l1block.operator_fee_scalar = Some(operator_fee_scalar); + l1block.operator_fee_constant = Some(operator_fee_constant); + + Ok(l1block) +} + /// An extension trait for [`L1BlockInfo`] that allows us to calculate the L1 cost of a transaction /// based off of the chain spec's activated hardfork. pub trait RethL1BlockInfo {