From 2514e4450d9a4f4cdf73a270eaf68e564a09c716 Mon Sep 17 00:00:00 2001 From: leruaa Date: Wed, 5 Feb 2025 09:45:39 -0800 Subject: [PATCH 1/2] feat: handle operator fee params --- crates/optimism/evm/src/l1.rs | 87 +++++++++++++++++++++++++- crates/optimism/rpc/src/eth/receipt.rs | 14 +++++ 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/crates/optimism/evm/src/l1.rs b/crates/optimism/evm/src/l1.rs index 5e35b34f2823..d4d1043790ff 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 { diff --git a/crates/optimism/rpc/src/eth/receipt.rs b/crates/optimism/rpc/src/eth/receipt.rs index 7f12d2595184..52d53691e8a4 100644 --- a/crates/optimism/rpc/src/eth/receipt.rs +++ b/crates/optimism/rpc/src/eth/receipt.rs @@ -85,6 +85,10 @@ pub struct OpReceiptFieldsBuilder { pub l1_blob_base_fee: Option, /// The current L1 blob base fee scalar. pub l1_blob_base_fee_scalar: Option, + /// The current operator fee scalar. + pub operator_fee_scalar: Option, + /// The current operator fee constant. + pub operator_fee_constant: Option, } impl OpReceiptFieldsBuilder { @@ -102,6 +106,8 @@ impl OpReceiptFieldsBuilder { l1_base_fee_scalar: None, l1_blob_base_fee: None, l1_blob_base_fee_scalar: None, + operator_fee_scalar: None, + operator_fee_constant: None, } } @@ -139,6 +145,10 @@ impl OpReceiptFieldsBuilder { self.l1_blob_base_fee = l1_block_info.l1_blob_base_fee.map(|fee| fee.saturating_to()); self.l1_blob_base_fee_scalar = l1_block_info.l1_blob_base_fee_scalar.map(|scalar| scalar.saturating_to()); + self.operator_fee_scalar = + l1_block_info.operator_fee_scalar.map(|scalar| scalar.saturating_to()); + self.operator_fee_constant = + l1_block_info.operator_fee_constant.map(|constant| constant.saturating_to()); Ok(self) } @@ -169,6 +179,8 @@ impl OpReceiptFieldsBuilder { l1_base_fee_scalar, l1_blob_base_fee, l1_blob_base_fee_scalar, + operator_fee_scalar, + operator_fee_constant, } = self; OpTransactionReceiptFields { @@ -180,6 +192,8 @@ impl OpReceiptFieldsBuilder { l1_base_fee_scalar, l1_blob_base_fee, l1_blob_base_fee_scalar, + operator_fee_scalar, + operator_fee_constant, }, deposit_nonce, deposit_receipt_version, From 702afcfab380ff466378ee9da1d118960585166f Mon Sep 17 00:00:00 2001 From: leruaa Date: Thu, 6 Feb 2025 02:08:15 -0800 Subject: [PATCH 2/2] fix: remove receipt part --- crates/optimism/evm/src/l1.rs | 2 +- crates/optimism/rpc/src/eth/receipt.rs | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/crates/optimism/evm/src/l1.rs b/crates/optimism/evm/src/l1.rs index d4d1043790ff..ab09a6e7b47e 100644 --- a/crates/optimism/evm/src/l1.rs +++ b/crates/optimism/evm/src/l1.rs @@ -189,7 +189,7 @@ pub fn parse_l1_info_tx_ecotone(data: &[u8]) -> Result, /// The current L1 blob base fee scalar. pub l1_blob_base_fee_scalar: Option, - /// The current operator fee scalar. - pub operator_fee_scalar: Option, - /// The current operator fee constant. - pub operator_fee_constant: Option, } impl OpReceiptFieldsBuilder { @@ -106,8 +102,6 @@ impl OpReceiptFieldsBuilder { l1_base_fee_scalar: None, l1_blob_base_fee: None, l1_blob_base_fee_scalar: None, - operator_fee_scalar: None, - operator_fee_constant: None, } } @@ -145,10 +139,6 @@ impl OpReceiptFieldsBuilder { self.l1_blob_base_fee = l1_block_info.l1_blob_base_fee.map(|fee| fee.saturating_to()); self.l1_blob_base_fee_scalar = l1_block_info.l1_blob_base_fee_scalar.map(|scalar| scalar.saturating_to()); - self.operator_fee_scalar = - l1_block_info.operator_fee_scalar.map(|scalar| scalar.saturating_to()); - self.operator_fee_constant = - l1_block_info.operator_fee_constant.map(|constant| constant.saturating_to()); Ok(self) } @@ -179,8 +169,6 @@ impl OpReceiptFieldsBuilder { l1_base_fee_scalar, l1_blob_base_fee, l1_blob_base_fee_scalar, - operator_fee_scalar, - operator_fee_constant, } = self; OpTransactionReceiptFields { @@ -192,8 +180,6 @@ impl OpReceiptFieldsBuilder { l1_base_fee_scalar, l1_blob_base_fee, l1_blob_base_fee_scalar, - operator_fee_scalar, - operator_fee_constant, }, deposit_nonce, deposit_receipt_version,