diff --git a/CHANGELOG.md b/CHANGELOG.md index eee9239d..9e39788d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.2](https://github.com/alloy-rs/op-alloy +/releases/tag/v0.3.2) - 2024-09-30 + +### Features + +- [consensus] Bincode compatibility ([#131](https://github.com/alloy-rs/op-alloy/issues/131)) + +### Miscellaneous Tasks + +- [genesis] Small README Update ([#128](https://github.com/alloy-rs/op-alloy/issues/128)) + ## [0.3.1](https://github.com/alloy-rs/op-alloy /releases/tag/v0.3.1) - 2024-09-30 @@ -12,6 +23,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - HashMap default +### Miscellaneous Tasks + +- Release 0.3.1 + ## [0.3.0](https://github.com/alloy-rs/op-alloy /releases/tag/v0.3.0) - 2024-09-30 diff --git a/Cargo.toml b/Cargo.toml index e223a4fa..7fdfd4a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["crates/*"] resolver = "2" [workspace.package] -version = "0.3.1" +version = "0.3.2" edition = "2021" rust-version = "1.81" authors = ["Alloy Contributors"] @@ -36,12 +36,12 @@ rustdoc-args = ["--cfg", "docsrs"] [workspace.dependencies] # Alloy -op-alloy-rpc-jsonrpsee = { version = "0.3.1", path = "crates/rpc-jsonrpsee" } -op-alloy-rpc-types = { version = "0.3.1", path = "crates/rpc-types" } -op-alloy-rpc-types-engine = { version = "0.3.1", path = "crates/rpc-types-engine" } -op-alloy-consensus = { version = "0.3.1", path = "crates/consensus", default-features = false } -op-alloy-genesis = { version = "0.3.1", path = "crates/genesis", default-features = false } -op-alloy-protocol = { version = "0.3.1", path = "crates/protocol", default-features = false } +op-alloy-rpc-jsonrpsee = { version = "0.3.2", path = "crates/rpc-jsonrpsee" } +op-alloy-rpc-types = { version = "0.3.2", path = "crates/rpc-types" } +op-alloy-rpc-types-engine = { version = "0.3.2", path = "crates/rpc-types-engine" } +op-alloy-consensus = { version = "0.3.2", path = "crates/consensus", default-features = false } +op-alloy-genesis = { version = "0.3.2", path = "crates/genesis", default-features = false } +op-alloy-protocol = { version = "0.3.2", path = "crates/protocol", default-features = false } alloy-rlp = { version = "0.3", default-features = false } alloy-primitives = { version = "0.8", default-features = false } diff --git a/crates/consensus/Cargo.toml b/crates/consensus/Cargo.toml index 1a705bd0..b8aeb763 100644 --- a/crates/consensus/Cargo.toml +++ b/crates/consensus/Cargo.toml @@ -26,6 +26,7 @@ arbitrary = { workspace = true, features = ["derive"], optional = true } # serde alloy-serde = { workspace = true, optional = true } serde = { workspace = true, features = ["derive"], optional = true } +serde_with = { version = "3.9", optional = true } # misc spin.workspace = true @@ -35,8 +36,10 @@ derive_more = { workspace = true, features = ["display"] } alloy-primitives = { workspace = true, features = ["rand"] } alloy-signer.workspace = true arbitrary = { workspace = true, features = ["derive"] } -tokio = { workspace = true, features = ["macros"] } +bincode = "1.3" +rand.workspace = true serde_json.workspace = true +tokio = { workspace = true, features = ["macros"] } [features] default = ["std"] @@ -45,3 +48,4 @@ k256 = ["alloy-primitives/k256", "alloy-consensus/k256"] kzg = ["alloy-eips/kzg", "alloy-consensus/kzg", "std"] arbitrary = ["std", "dep:arbitrary", "alloy-consensus/arbitrary", "alloy-eips/arbitrary", "alloy-primitives/rand"] serde = ["dep:serde", "dep:alloy-serde", "alloy-primitives/serde", "alloy-consensus/serde", "alloy-eips/serde"] +serde-bincode-compat = ["serde_with"] diff --git a/crates/consensus/src/lib.rs b/crates/consensus/src/lib.rs index 9e0da8fd..16259f37 100644 --- a/crates/consensus/src/lib.rs +++ b/crates/consensus/src/lib.rs @@ -24,3 +24,15 @@ pub use hardforks::Hardforks; mod block; pub use block::OpBlock; + +/// Bincode-compatible serde implementations for consensus types. +/// +/// `bincode` crate doesn't work well with optionally serializable serde fields, but some of the +/// consensus types require optional serialization for RPC compatibility. This module makes so that +/// all fields are serialized. +/// +/// Read more: +#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))] +pub mod serde_bincode_compat { + pub use super::transaction::serde_bincode_compat::TxDeposit; +} diff --git a/crates/consensus/src/transaction/deposit.rs b/crates/consensus/src/transaction/deposit.rs index 01a7699b..0041e747 100644 --- a/crates/consensus/src/transaction/deposit.rs +++ b/crates/consensus/src/transaction/deposit.rs @@ -356,3 +356,120 @@ mod tests { assert!(total_len > len_without_header); } } + +/// Bincode-compatible [`TxDeposit`] serde implementation. +#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))] +pub(super) mod serde_bincode_compat { + use alloc::borrow::Cow; + use alloy_primitives::{Address, Bytes, TxKind, B256, U256}; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + use serde_with::{DeserializeAs, SerializeAs}; + + /// Bincode-compatible [`super::TxDeposit`] serde implementation. + /// + /// Intended to use with the [`serde_with::serde_as`] macro in the following way: + /// ```rust + /// use op_alloy_consensus::{serde_bincode_compat, TxDeposit}; + /// use serde::{Deserialize, Serialize}; + /// use serde_with::serde_as; + /// + /// #[serde_as] + /// #[derive(Serialize, Deserialize)] + /// struct Data { + /// #[serde_as(as = "serde_bincode_compat::TxDeposit")] + /// transaction: TxDeposit, + /// } + /// ``` + #[derive(Debug, Serialize, Deserialize)] + pub struct TxDeposit<'a> { + source_hash: B256, + from: Address, + #[serde(default)] + to: TxKind, + #[serde(default)] + mint: Option, + value: U256, + gas_limit: u64, + is_system_transaction: bool, + input: Cow<'a, Bytes>, + } + + impl<'a> From<&'a super::TxDeposit> for TxDeposit<'a> { + fn from(value: &'a super::TxDeposit) -> Self { + Self { + source_hash: value.source_hash, + from: value.from, + to: value.to, + mint: value.mint, + value: value.value, + gas_limit: value.gas_limit, + is_system_transaction: value.is_system_transaction, + input: Cow::Borrowed(&value.input), + } + } + } + + impl<'a> From> for super::TxDeposit { + fn from(value: TxDeposit<'a>) -> Self { + Self { + source_hash: value.source_hash, + from: value.from, + to: value.to, + mint: value.mint, + value: value.value, + gas_limit: value.gas_limit, + is_system_transaction: value.is_system_transaction, + input: value.input.into_owned(), + } + } + } + + impl<'a> SerializeAs for TxDeposit<'a> { + fn serialize_as(source: &super::TxDeposit, serializer: S) -> Result + where + S: Serializer, + { + TxDeposit::from(source).serialize(serializer) + } + } + + impl<'de> DeserializeAs<'de, super::TxDeposit> for TxDeposit<'de> { + fn deserialize_as(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + TxDeposit::deserialize(deserializer).map(Into::into) + } + } + + #[cfg(test)] + mod tests { + use arbitrary::Arbitrary; + use rand::Rng; + use serde::{Deserialize, Serialize}; + use serde_with::serde_as; + + use super::super::{serde_bincode_compat, TxDeposit}; + + #[test] + fn test_tx_deposit_bincode_roundtrip() { + #[serde_as] + #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] + struct Data { + #[serde_as(as = "serde_bincode_compat::TxDeposit")] + transaction: TxDeposit, + } + + let mut bytes = [0u8; 1024]; + rand::thread_rng().fill(bytes.as_mut_slice()); + let data = Data { + transaction: TxDeposit::arbitrary(&mut arbitrary::Unstructured::new(&bytes)) + .unwrap(), + }; + + let encoded = bincode::serialize(&data).unwrap(); + let decoded: Data = bincode::deserialize(&encoded).unwrap(); + assert_eq!(decoded, data); + } + } +} diff --git a/crates/consensus/src/transaction/mod.rs b/crates/consensus/src/transaction/mod.rs index acbe394a..2b3816f4 100644 --- a/crates/consensus/src/transaction/mod.rs +++ b/crates/consensus/src/transaction/mod.rs @@ -12,3 +12,9 @@ pub use source::{ DepositSourceDomain, DepositSourceDomainIdentifier, L1InfoDepositSource, UpgradeDepositSource, UserDepositSource, }; + +/// Bincode-compatible serde implementations for transaction types. +#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))] +pub(super) mod serde_bincode_compat { + pub use super::deposit::serde_bincode_compat::TxDeposit; +} diff --git a/crates/protocol/src/lib.rs b/crates/protocol/src/lib.rs index b78d9243..1edf8579 100644 --- a/crates/protocol/src/lib.rs +++ b/crates/protocol/src/lib.rs @@ -27,7 +27,7 @@ pub use frame::{ }; mod utils; -pub use utils::starts_with_2718_deposit; +pub use utils::{starts_with_2718_deposit, to_system_config, OpBlockConversionError}; mod channel; pub use channel::{ diff --git a/crates/protocol/src/utils.rs b/crates/protocol/src/utils.rs index 166f7509..895af25f 100644 --- a/crates/protocol/src/utils.rs +++ b/crates/protocol/src/utils.rs @@ -1,5 +1,13 @@ //! Utility methods used by protocol types. +use crate::{ + block_info::DecodeError, L1BlockInfoBedrock, L1BlockInfoEcotone, L1BlockInfoHolocene, + L1BlockInfoTx, +}; +use alloy_primitives::B256; +use op_alloy_consensus::{OpBlock, OpTxEnvelope}; +use op_alloy_genesis::{RollupConfig, SystemConfig}; + /// Returns if the given `value` is a deposit transaction. pub fn starts_with_2718_deposit(value: &B) -> bool where @@ -8,6 +16,102 @@ where value.as_ref().first() == Some(&0x7E) } +/// An error encountered during [OpBlock] conversion. +#[derive(Debug, derive_more::Display)] +pub enum OpBlockConversionError { + /// Invalid genesis hash. + #[display("Invalid genesis hash. Expected {_0}, got {_1}")] + InvalidGenesisHash(B256, B256), + /// Invalid transaction type. + #[display("First payload transaction has unexpected type: {_0}")] + InvalidTxType(u8), + /// L1 Info error + #[display("Failed to decode L1 info: {_0}")] + L1InfoError(DecodeError), + /// Missing system config in genesis block. + #[display("Missing system config in genesis block")] + MissingSystemConfigGenesis, + /// Empty transactions. + #[display("Empty transactions in payload. Block hash: {_0}")] + EmptyTransactions(B256), +} + +impl core::error::Error for OpBlockConversionError { + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + match self { + Self::L1InfoError(err) => Some(err), + _ => None, + } + } +} + +impl From for OpBlockConversionError { + fn from(e: DecodeError) -> Self { + Self::L1InfoError(e) + } +} + +/// Converts the [OpBlock] to a partial [SystemConfig]. +pub fn to_system_config( + block: &OpBlock, + rollup_config: &RollupConfig, +) -> Result { + if block.header.number == rollup_config.genesis.l2.number { + if block.header.hash_slow() != rollup_config.genesis.l2.hash { + return Err(OpBlockConversionError::InvalidGenesisHash( + rollup_config.genesis.l2.hash, + block.header.hash_slow(), + )); + } + return rollup_config + .genesis + .system_config + .ok_or(OpBlockConversionError::MissingSystemConfigGenesis); + } + + if block.body.transactions.is_empty() { + return Err(OpBlockConversionError::EmptyTransactions(block.header.hash_slow())); + } + let OpTxEnvelope::Deposit(ref tx) = block.body.transactions[0] else { + return Err(OpBlockConversionError::InvalidTxType( + block.body.transactions[0].tx_type() as u8 + )); + }; + + let l1_info = L1BlockInfoTx::decode_calldata(tx.input.as_ref())?; + let l1_fee_scalar = match l1_info { + L1BlockInfoTx::Bedrock(L1BlockInfoBedrock { l1_fee_scalar, .. }) => l1_fee_scalar, + L1BlockInfoTx::Ecotone(L1BlockInfoEcotone { + base_fee_scalar, + blob_base_fee_scalar, + .. + }) + | L1BlockInfoTx::Holocene(L1BlockInfoHolocene { + base_fee_scalar, + blob_base_fee_scalar, + .. + }) => { + // Translate Ecotone values back into encoded scalar if needed. + // We do not know if it was derived from a v0 or v1 scalar, + // but v1 is fine, a 0 blob base fee has the same effect. + let mut buf = B256::ZERO; + buf[0] = 0x01; + buf[24..28].copy_from_slice(blob_base_fee_scalar.to_be_bytes().as_ref()); + buf[28..32].copy_from_slice(base_fee_scalar.to_be_bytes().as_ref()); + buf.into() + } + }; + + Ok(SystemConfig { + batcher_address: l1_info.batcher_address(), + overhead: l1_info.l1_fee_overhead(), + scalar: l1_fee_scalar, + gas_limit: block.header.gas_limit, + base_fee_scalar: None, + blob_base_fee_scalar: None, + }) +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/rpc-types-engine/Cargo.toml b/crates/rpc-types-engine/Cargo.toml index 1d62087b..9dcd9a51 100644 --- a/crates/rpc-types-engine/Cargo.toml +++ b/crates/rpc-types-engine/Cargo.toml @@ -15,12 +15,9 @@ exclude.workspace = true workspace = true [dependencies] -alloy-eips.workspace = true alloy-primitives.workspace = true alloy-rpc-types-engine.workspace = true op-alloy-protocol.workspace = true -op-alloy-genesis.workspace = true -op-alloy-consensus.workspace = true derive_more = { workspace = true, features = ["display"] } @@ -37,14 +34,10 @@ std = [ "alloy-primitives/std", "alloy-rpc-types-engine/std", "op-alloy-protocol/std", - "op-alloy-genesis/std", - "op-alloy-consensus/std", ] serde = [ "dep:serde", "dep:alloy-serde", - "op-alloy-genesis/serde", "op-alloy-protocol/serde", "alloy-rpc-types-engine/serde", - "op-alloy-consensus/serde", ] diff --git a/crates/rpc-types-engine/src/errors.rs b/crates/rpc-types-engine/src/errors.rs deleted file mode 100644 index 0499f44f..00000000 --- a/crates/rpc-types-engine/src/errors.rs +++ /dev/null @@ -1,107 +0,0 @@ -//! Error types for conversions between Optimism Execution Payload Envelope -//! types and external types. - -use alloy_eips::eip2718::Eip2718Error; -use alloy_primitives::B256; -use op_alloy_protocol::block_info::DecodeError; - -/// An error that can occur when converting an [crate::OptimismExecutionPayloadEnvelopeV4] to an -/// [op_alloy_protocol::L2BlockInfo]. -#[derive(Debug, derive_more::Display)] -pub enum ToL2BlockRefError { - /// The genesis block hash does not match the expected value. - #[display("Invalid genesis hash")] - InvalidGenesisHash, - /// The L2 block is missing the L1 info deposit transaction. - #[display("L2 block is missing L1 info deposit transaction ({_0})")] - MissingL1InfoDeposit(B256), - /// The first payload transaction has an unexpected type. - #[display("First payload transaction has unexpected type: {_0}")] - UnexpectedTxType(u8), - /// Failed to decode the first transaction into an [op_alloy_consensus::OpTxEnvelope]. - #[display("Failed to decode the first transaction into an OpTxEnvelope: {_0}")] - TxEnvelopeDecodeError(Eip2718Error), - /// The first payload transaction is not a deposit transaction. - #[display("First payload transaction is not a deposit transaction, type: {_0}")] - FirstTxNonDeposit(u8), - /// Failed to decode the [op_alloy_protocol::L1BlockInfoTx] from the deposit transaction. - #[display("Failed to decode the L1BlockInfoTx from the deposit transaction: {_0}")] - BlockInfoDecodeError(DecodeError), -} - -// Since `Eip2718Error` uses an msrv prior to rust `1.81`, the `core::error::Error` type -// is not stabalized and `Eip2718Error` only implements `std::error::Error` and not -// `core::error::Error`. So we need to implement `std::error::Error` to provide the `Eip2718Error` -// as a source when the `std` feature is enabled. -#[cfg(feature = "std")] -impl std::error::Error for ToL2BlockRefError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Self::TxEnvelopeDecodeError(err) => Some(err), - Self::BlockInfoDecodeError(err) => Some(err), - _ => None, - } - } -} - -#[cfg(not(feature = "std"))] -impl core::error::Error for ToL2BlockRefError { - fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { - match self { - Self::BlockInfoDecodeError(err) => Some(err), - _ => None, - } - } -} - -/// An error that can occur when converting an [crate::OptimismExecutionPayloadEnvelopeV4] to a -/// [op_alloy_genesis::SystemConfig]. -#[derive(Debug, derive_more::Display)] -pub enum ToSystemConfigError { - /// The genesis block hash does not match the expected value. - #[display("Invalid genesis hash")] - InvalidGenesisHash, - /// The L2 block is missing the L1 info deposit transaction. - #[display("L2 block is missing L1 info deposit transaction ({_0})")] - MissingL1InfoDeposit(B256), - /// The first payload transaction has an unexpected type. - #[display("First payload transaction has unexpected type: {_0}")] - UnexpectedTxType(u8), - /// Failed to decode the first transaction into an [op_alloy_consensus::OpTxEnvelope]. - #[display("Failed to decode the first transaction into an OpTxEnvelope: {_0}")] - TxEnvelopeDecodeError(Eip2718Error), - /// The first payload transaction is not a deposit transaction. - #[display("First payload transaction is not a deposit transaction, type: {_0}")] - FirstTxNonDeposit(u8), - /// Failed to decode the [op_alloy_protocol::L1BlockInfoTx] from the deposit transaction. - #[display("Failed to decode the L1BlockInfoTx from the deposit transaction: {_0}")] - BlockInfoDecodeError(DecodeError), - /// Missing system config in the genesis block. - #[display("Missing system config in the genesis block")] - MissingSystemConfig, -} - -// Since `Eip2718Error` uses an msrv prior to rust `1.81`, the `core::error::Error` type -// is not stabalized and `Eip2718Error` only implements `std::error::Error` and not -// `core::error::Error`. So we need to implement `std::error::Error` to provide the `Eip2718Error` -// as a source when the `std` feature is enabled. -#[cfg(feature = "std")] -impl std::error::Error for ToSystemConfigError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Self::TxEnvelopeDecodeError(err) => Some(err), - Self::BlockInfoDecodeError(err) => Some(err), - _ => None, - } - } -} - -#[cfg(not(feature = "std"))] -impl core::error::Error for ToSystemConfigError { - fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { - match self { - Self::BlockInfoDecodeError(err) => Some(err), - _ => None, - } - } -} diff --git a/crates/rpc-types-engine/src/lib.rs b/crates/rpc-types-engine/src/lib.rs index 54f58e6d..14412fe1 100644 --- a/crates/rpc-types-engine/src/lib.rs +++ b/crates/rpc-types-engine/src/lib.rs @@ -9,17 +9,6 @@ extern crate alloc; -pub use alloy_rpc_types_engine::ExecutionPayloadV1; -pub use op_alloy_genesis::{ChainGenesis, RollupConfig, SystemConfig}; -pub use op_alloy_protocol::L2BlockInfo; - -use alloy_eips::eip2718::Decodable2718; -use alloy_primitives::B256; -use op_alloy_consensus::{OpTxEnvelope, OpTxType}; -use op_alloy_protocol::{ - BlockInfo, L1BlockInfoBedrock, L1BlockInfoEcotone, L1BlockInfoHolocene, L1BlockInfoTx, -}; - mod attributes; pub use attributes::{OptimismAttributesWithParent, OptimismPayloadAttributes}; @@ -33,142 +22,3 @@ mod superchain; pub use superchain::{ ProtocolVersion, ProtocolVersionError, ProtocolVersionFormatV0, SuperchainSignal, }; - -mod errors; -pub use errors::{ToL2BlockRefError, ToSystemConfigError}; - -/// Converts a payload into its most inner [ExecutionPayloadV1]. -pub trait AsInnerPayload { - /// Converts the payload into its most inner [ExecutionPayloadV1]. - fn as_v1_payload(&self) -> alloc::borrow::Cow<'_, ExecutionPayloadV1>; -} - -/// Defines conversion utility methods for Optimism-specific payloads. -pub trait OptimismPayloadUtils { - /// Converts the payload into an [L2BlockInfo]. - /// - /// This method creates the [L2BlockInfo] using the inner payload - /// fetched with the [AsInnerPayload::as_v1_payload] method. - /// - /// If the payload is the genesis block, it will return the genesis block info. - /// Otherwise, it will return the L2 block info from the first deposit transaction. - fn to_l2_block_info(&self, genesis: &ChainGenesis) -> Result; - - /// Converts the payload into a [SystemConfig]. - /// - /// This method creates the [SystemConfig] using the inner payload - /// fetched with the [AsInnerPayload::as_v1_payload] method. - /// - /// If the payload is the genesis block, it will return the system config from the genesis - /// block. Otherwise, it will return the system config from the first deposit transaction. - fn to_system_config(&self, genesis: &ChainGenesis) - -> Result; -} - -impl OptimismPayloadUtils for T -where - T: AsInnerPayload, -{ - fn to_l2_block_info(&self, genesis: &ChainGenesis) -> Result { - let inner_payload = self.as_v1_payload(); - - let (l1_origin, sequence_number) = if inner_payload.block_number == genesis.l2.number { - if inner_payload.block_hash != genesis.l2.hash { - return Err(ToL2BlockRefError::InvalidGenesisHash); - } - (genesis.l1, 0) - } else { - if inner_payload.transactions.is_empty() { - return Err(ToL2BlockRefError::MissingL1InfoDeposit(inner_payload.block_hash)); - } - - let ty = inner_payload.transactions[0][0]; - if ty != OpTxType::Deposit as u8 { - return Err(ToL2BlockRefError::UnexpectedTxType(ty)); - } - let tx = OpTxEnvelope::decode_2718(&mut inner_payload.transactions[0].as_ref()) - .map_err(ToL2BlockRefError::TxEnvelopeDecodeError)?; - - let OpTxEnvelope::Deposit(tx) = tx else { - return Err(ToL2BlockRefError::FirstTxNonDeposit(tx.tx_type().into())); - }; - - let l1_info = L1BlockInfoTx::decode_calldata(tx.input.as_ref()) - .map_err(ToL2BlockRefError::BlockInfoDecodeError)?; - (l1_info.id(), l1_info.sequence_number()) - }; - - Ok(L2BlockInfo { - block_info: BlockInfo { - hash: inner_payload.block_hash, - number: inner_payload.block_number, - parent_hash: inner_payload.parent_hash, - timestamp: inner_payload.timestamp, - }, - l1_origin, - seq_num: sequence_number, - }) - } - - fn to_system_config( - &self, - genesis: &ChainGenesis, - ) -> Result { - let inner_payload = self.as_v1_payload(); - - if inner_payload.block_number == genesis.l2.number { - if inner_payload.block_hash != genesis.l2.hash { - return Err(ToSystemConfigError::InvalidGenesisHash); - } - return genesis.system_config.ok_or(ToSystemConfigError::MissingSystemConfig); - } - - if inner_payload.transactions.is_empty() { - return Err(ToSystemConfigError::MissingL1InfoDeposit(inner_payload.block_hash)); - } - let ty = inner_payload.transactions[0][0]; - if ty != OpTxType::Deposit as u8 { - return Err(ToSystemConfigError::UnexpectedTxType(ty)); - } - let tx = OpTxEnvelope::decode_2718(&mut inner_payload.transactions[0].as_ref()) - .map_err(ToSystemConfigError::TxEnvelopeDecodeError)?; - - let OpTxEnvelope::Deposit(tx) = tx else { - return Err(ToSystemConfigError::FirstTxNonDeposit(tx.tx_type().into())); - }; - - let l1_info = L1BlockInfoTx::decode_calldata(tx.input.as_ref()) - .map_err(ToSystemConfigError::BlockInfoDecodeError)?; - let l1_fee_scalar = match l1_info { - L1BlockInfoTx::Bedrock(L1BlockInfoBedrock { l1_fee_scalar, .. }) => l1_fee_scalar, - L1BlockInfoTx::Ecotone(L1BlockInfoEcotone { - base_fee_scalar, - blob_base_fee_scalar, - .. - }) - | L1BlockInfoTx::Holocene(L1BlockInfoHolocene { - base_fee_scalar, - blob_base_fee_scalar, - .. - }) => { - // Translate Ecotone values back into encoded scalar if needed. - // We do not know if it was derived from a v0 or v1 scalar, - // but v1 is fine, a 0 blob base fee has the same effect. - let mut buf = B256::ZERO; - buf[0] = 0x01; - buf[24..28].copy_from_slice(blob_base_fee_scalar.to_be_bytes().as_ref()); - buf[28..32].copy_from_slice(base_fee_scalar.to_be_bytes().as_ref()); - buf.into() - } - }; - - Ok(SystemConfig { - batcher_address: l1_info.batcher_address(), - overhead: l1_info.l1_fee_overhead(), - scalar: l1_fee_scalar, - gas_limit: inner_payload.gas_limit, - base_fee_scalar: None, - blob_base_fee_scalar: None, - }) - } -} diff --git a/crates/rpc-types-engine/src/payload_v3.rs b/crates/rpc-types-engine/src/payload_v3.rs index 8fe14b45..94f33a48 100644 --- a/crates/rpc-types-engine/src/payload_v3.rs +++ b/crates/rpc-types-engine/src/payload_v3.rs @@ -1,7 +1,7 @@ //! Optimism execution payload envelope V3. use alloy_primitives::{B256, U256}; -use alloy_rpc_types_engine::{BlobsBundleV1, ExecutionPayloadV1, ExecutionPayloadV3}; +use alloy_rpc_types_engine::{BlobsBundleV1, ExecutionPayloadV3}; /// This structure maps for the return value of `engine_getPayload` of the beacon chain spec, for /// V3. @@ -25,13 +25,6 @@ pub struct OptimismExecutionPayloadEnvelopeV3 { pub parent_beacon_block_root: B256, } -impl crate::AsInnerPayload for OptimismExecutionPayloadEnvelopeV3 { - /// Returns the inner [ExecutionPayloadV1] from the envelope. - fn as_v1_payload(&self) -> alloc::borrow::Cow<'_, ExecutionPayloadV1> { - alloc::borrow::Cow::Borrowed(&self.execution_payload.payload_inner.payload_inner) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/rpc-types-engine/src/payload_v4.rs b/crates/rpc-types-engine/src/payload_v4.rs index 8e5c1a75..d1e89be1 100644 --- a/crates/rpc-types-engine/src/payload_v4.rs +++ b/crates/rpc-types-engine/src/payload_v4.rs @@ -1,7 +1,7 @@ //! Optimism execution payload envelope V3. use alloy_primitives::{B256, U256}; -use alloy_rpc_types_engine::{BlobsBundleV1, ExecutionPayloadV1, ExecutionPayloadV4}; +use alloy_rpc_types_engine::{BlobsBundleV1, ExecutionPayloadV4}; /// This structure maps for the return value of `engine_getPayload` of the beacon chain spec, for /// V4. @@ -25,15 +25,6 @@ pub struct OptimismExecutionPayloadEnvelopeV4 { pub parent_beacon_block_root: B256, } -impl crate::AsInnerPayload for OptimismExecutionPayloadEnvelopeV4 { - /// Returns the inner [ExecutionPayloadV1] from the envelope. - fn as_v1_payload(&self) -> alloc::borrow::Cow<'_, ExecutionPayloadV1> { - alloc::borrow::Cow::Borrowed( - &self.execution_payload.payload_inner.payload_inner.payload_inner, - ) - } -} - #[cfg(test)] mod tests { use super::*;