diff --git a/Cargo.lock b/Cargo.lock index 6e53793c..4a39c2c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,6 +56,35 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "alloy-sol-macro" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e92100dee7fd1e44abbe0ef6607f18758cf0ad4e483f4c65ff5c8d85428a6d" +dependencies = [ + "const-hex", + "dunce", + "heck", + "indexmap", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.48", + "syn-solidity", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-types" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e7c6a8c492b1d6a4f92a8fc6a13cf39473978dd7d459d7221969ce5a73d97cd" +dependencies = [ + "alloy-primitives", + "alloy-sol-macro", + "const-hex", +] + [[package]] name = "anyhow" version = "1.0.79" @@ -174,6 +203,18 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.8" @@ -196,6 +237,18 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.3.5" @@ -217,6 +270,16 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "indexmap" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "itoa" version = "1.0.10" @@ -238,6 +301,7 @@ version = "0.0.1" dependencies = [ "alloy-primitives", "alloy-rlp", + "alloy-sol-types", "anyhow", "async-trait", "serde", @@ -369,6 +433,12 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -381,6 +451,30 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.78" @@ -593,6 +687,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn-solidity" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e656cbcef8a77543b5accbd76f60f9e0bc4be364b0aba4263a6f313f8a355511" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "tempfile" version = "3.10.0" @@ -662,6 +768,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/crates/derive/Cargo.toml b/crates/derive/Cargo.toml index 7b743b0f..d628856c 100644 --- a/crates/derive/Cargo.toml +++ b/crates/derive/Cargo.toml @@ -15,6 +15,7 @@ anyhow.workspace = true # External alloy-primitives = { version = "0.6.3", default-features = false, features = ["rlp"] } alloy-rlp = { version = "0.3.4", default-features = false, features = ["derive"] } +alloy-sol-types = { version = "0.6.3", default-features = false } async-trait = "0.1.77" # Optional diff --git a/crates/derive/src/stages/l1_traversal.rs b/crates/derive/src/stages/l1_traversal.rs index 8a224e27..1e7cad4c 100644 --- a/crates/derive/src/stages/l1_traversal.rs +++ b/crates/derive/src/stages/l1_traversal.rs @@ -8,11 +8,11 @@ use anyhow::{anyhow, bail, Result}; /// The L1 traversal stage of the derivation pipeline. #[derive(Debug, Clone, Copy)] -pub struct L1Traversal { +pub struct L1Traversal { /// The current block in the traversal stage. block: Option, /// The data source for the traversal stage. - data_source: F, + data_source: Provider, /// Signals whether or not the traversal stage has been completed. done: bool, /// The system config diff --git a/crates/derive/src/types/eips/mod.rs b/crates/derive/src/types/eips/mod.rs index fdcbc6b1..8513380a 100644 --- a/crates/derive/src/types/eips/mod.rs +++ b/crates/derive/src/types/eips/mod.rs @@ -12,6 +12,4 @@ pub mod eip4788; pub mod eip4844; pub use eip4844::{calc_blob_gasprice, calc_excess_blob_gas}; -pub mod deposit; - pub mod merge; diff --git a/crates/derive/src/types/genesis.rs b/crates/derive/src/types/genesis.rs new file mode 100644 index 00000000..4acd3f56 --- /dev/null +++ b/crates/derive/src/types/genesis.rs @@ -0,0 +1,19 @@ +//! This module contains the [Genesis] type. + +use super::{BlockId, SystemConfig}; + +/// Represents the genesis state of the rollup. +#[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Genesis { + /// The L1 block that the rollup starts *after* (no derived transactions) + pub l1: BlockId, + /// The L2 block the rollup starts from (no transactions, pre-configured state) + pub l2: BlockId, + /// Timestamp of the L2 block. + pub timestamp: u64, + /// Initial system configuration values. + /// The L2 genesis block may not include transactions, and thus cannot encode the config values, + /// unlike later L2 blocks. + pub system_config: SystemConfig, +} diff --git a/crates/derive/src/types/mod.rs b/crates/derive/src/types/mod.rs index 5c89290f..52fc6be1 100644 --- a/crates/derive/src/types/mod.rs +++ b/crates/derive/src/types/mod.rs @@ -7,8 +7,10 @@ mod rollup_config; pub use rollup_config::RollupConfig; mod transaction; +pub use transaction::{TxDeposit, TxEip1559, TxEip2930, TxEip4844, TxEnvelope, TxLegacy, TxType}; mod network; +pub use network::{Receipt as NetworkReceipt, Sealable, Sealed, Transaction, TxKind}; mod header; pub use header::{Header, EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH}; @@ -20,3 +22,10 @@ mod receipt; pub use receipt::{Receipt, ReceiptWithBloom}; mod eips; +pub use eips::{ + calc_blob_gasprice, calc_excess_blob_gas, calc_next_block_base_fee, eip1559, eip2718, eip2930, + eip4788, eip4844, +}; + +mod genesis; +pub use genesis::Genesis; diff --git a/crates/derive/src/types/network/mod.rs b/crates/derive/src/types/network/mod.rs index 2817fcc3..a36d88a1 100644 --- a/crates/derive/src/types/network/mod.rs +++ b/crates/derive/src/types/network/mod.rs @@ -12,15 +12,3 @@ pub use transaction::{Eip1559Transaction, Signed, Transaction, TxKind}; mod receipt; pub use receipt::Receipt; - -/// A list of transactions, either hydrated or hashes. -// #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -// #[serde(untagged)] -pub enum TransactionList { - /// Hashes only. - Hashes(Vec), - /// Hydrated tx objects. - Hydrated(Vec), - /// Special case for uncle response - Uncled, -} diff --git a/crates/derive/src/types/rollup_config.rs b/crates/derive/src/types/rollup_config.rs index 3f55263d..c43e8bd1 100644 --- a/crates/derive/src/types/rollup_config.rs +++ b/crates/derive/src/types/rollup_config.rs @@ -1,10 +1,14 @@ //! This module contains the [RollupConfig] type. +use super::Genesis; use alloy_primitives::Address; /// The Rollup configuration. #[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct RollupConfig { + /// The genesis state of the rollup. + pub genesis: Genesis, /// The block time of the L2, in seconds. pub block_time: u64, /// Sequencer batches may not be more than MaxSequencerDrift seconds after @@ -14,7 +18,7 @@ pub struct RollupConfig { /// the L2 time may still grow beyond this difference. pub max_sequencer_drift: u64, /// The sequencer window size. - pub sequencer_window_size: u64, + pub seq_window_size: u64, /// Number of L1 blocks between when a channel can be opened and when it can be closed. pub channel_timeout: u64, /// The L1 chain ID @@ -25,21 +29,27 @@ pub struct RollupConfig { /// a pre-mainnet Bedrock change that addresses findings of the Sherlock contest related to deposit attributes. /// "Regolith" is the loose deposited rock that sits on top of Bedrock. /// Active if regolith_time != None && L2 block timestamp >= Some(regolith_time), inactive otherwise. + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub regolith_time: Option, /// `canyon_time` sets the activation time of the Canyon network upgrade. /// Active if `canyon_time` != None && L2 block timestamp >= Some(canyon_time), inactive otherwise. + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub canyon_time: Option, /// `delta_time` sets the activation time of the Delta network upgrade. /// Active if `delta_time` != None && L2 block timestamp >= Some(delta_time), inactive otherwise. + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub delta_time: Option, /// `ecotone_time` sets the activation time of the Ecotone network upgrade. /// Active if `ecotone_time` != None && L2 block timestamp >= Some(ecotone_time), inactive otherwise. + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub ecotone_time: Option, /// `fjord_time` sets the activation time of the Fjord network upgrade. /// Active if `fjord_time` != None && L2 block timestamp >= Some(fjord_time), inactive otherwise. + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub fjord_time: Option, /// `interop_time` sets the activation time for an experimental feature-set, activated like a hardfork. /// Active if `interop_time` != None && L2 block timestamp >= Some(interop_time), inactive otherwise. + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub interop_time: Option, /// `batch_inbox_address` is the L1 address that batches are sent to. pub batch_inbox_address: Address, @@ -50,7 +60,67 @@ pub struct RollupConfig { /// `protocol_versions_address` is the L1 address that the protocol versions are stored at. pub protocol_versions_address: Address, /// `blobs_enabled_l1_timestamp` is the timestamp to start reading blobs as a batch data source. Optional. + #[cfg_attr( + feature = "serde", + serde(rename = "blobs_data", skip_serializing_if = "Option::is_none") + )] pub blobs_enabled_l1_timestamp: Option, /// `da_challenge_address` is the L1 address that the data availability challenge contract is stored at. + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub da_challenge_address: Option
, } + +impl RollupConfig { + /// Returns true if Regolith is active at the given timestamp. + pub fn is_regolith_active(&self, timestamp: u64) -> bool { + self.regolith_time.map_or(false, |t| timestamp >= t) + } + + /// Returns true if Canyon is active at the given timestamp. + pub fn is_canyon_active(&self, timestamp: u64) -> bool { + self.canyon_time.map_or(false, |t| timestamp >= t) + } + + /// Returns true if Delta is active at the given timestamp. + pub fn is_delta_active(&self, timestamp: u64) -> bool { + self.delta_time.map_or(false, |t| timestamp >= t) + } + + /// Returns true if Ecotone is active at the given timestamp. + pub fn is_ecotone_active(&self, timestamp: u64) -> bool { + self.ecotone_time.map_or(false, |t| timestamp >= t) + } + + /// Returns true if Fjord is active at the given timestamp. + pub fn is_fjord_active(&self, timestamp: u64) -> bool { + self.fjord_time.map_or(false, |t| timestamp >= t) + } + + /// Returns true if Interop is active at the given timestamp. + pub fn is_interop_active(&self, timestamp: u64) -> bool { + self.interop_time.map_or(false, |t| timestamp >= t) + } + + /// Checks the scalar value in Ecotone. + pub fn check_ecotone_l1_system_config_scalar(scalar: [u8; 32]) -> Result<(), &'static str> { + let version_byte = scalar[0]; + match version_byte { + 0 => { + if scalar[1..28] != [0; 27] { + return Err("Bedrock scalar padding not empty"); + } + Ok(()) + } + 1 => { + if scalar[1..24] != [0; 23] { + return Err("Invalid version 1 scalar padding"); + } + Ok(()) + } + _ => { + // ignore the event if it's an unknown scalar format + Err("Unrecognized scalar version") + } + } + } +} diff --git a/crates/derive/src/types/system_config.rs b/crates/derive/src/types/system_config.rs index ecc12bd7..a1772c1d 100644 --- a/crates/derive/src/types/system_config.rs +++ b/crates/derive/src/types/system_config.rs @@ -2,18 +2,19 @@ use super::{Receipt, RollupConfig}; use alloy_primitives::{address, b256, Address, Log, B256, U256}; -use anyhow::Result; - -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; +use alloy_sol_types::{sol, SolType, SolValue}; +use anyhow::{anyhow, bail, Result}; /// `keccak256("ConfigUpdate(uint256,uint8,bytes)")` const CONFIG_UPDATE_TOPIC: B256 = b256!("1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be"); +/// The initial version of the system config event log. +const CONFIG_UPDATE_EVENT_VERSION_0: B256 = B256::ZERO; + /// Optimism system config contract values #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SystemConfig { /// Batch sender address pub batch_sender: Address, @@ -27,6 +28,30 @@ pub struct SystemConfig { pub unsafe_block_signer: Address, } +/// Represents type of update to the system config. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u64)] +pub enum SystemConfigUpdateType { + Batcher = 0, + GasConfig = 1, + GasLimit = 2, + UnsafeBlockSigner = 3, +} + +impl TryFrom for SystemConfigUpdateType { + type Error = anyhow::Error; + + fn try_from(value: u64) -> core::prelude::v1::Result { + match value { + 0 => Ok(SystemConfigUpdateType::Batcher), + 1 => Ok(SystemConfigUpdateType::GasConfig), + 2 => Ok(SystemConfigUpdateType::GasLimit), + 3 => Ok(SystemConfigUpdateType::UnsafeBlockSigner), + _ => bail!("Invalid SystemConfigUpdateType value: {}", value), + } + } +} + impl SystemConfig { /// Filters all L1 receipts to find config updates and applies the config updates. pub fn update_with_receipts( @@ -42,8 +67,7 @@ impl SystemConfig { for log in receipt.logs.iter() { let topics = log.topics(); - // TODO: System config address isn't in this type, replace `Address::ZERO`. - if log.address == Address::ZERO + if log.address == rollup_config.l1_system_config_address && !topics.is_empty() && topics[0] == CONFIG_UPDATE_TOPIC { @@ -54,15 +78,134 @@ impl SystemConfig { Ok(()) } - /// Processes a single config update log. - fn process_config_update_log(&mut self, _: &Log, _: &RollupConfig, _: u64) -> Result<()> { - todo!("Process log update event."); + /// Decodes an EVM log entry emitted by the system config contract and applies it as a [SystemConfig] change. + /// + /// Parse log data for: + /// + /// ```text + ///event ConfigUpdate( + /// uint256 indexed version, + /// UpdateType indexed updateType, + /// bytes data + ///); + /// ``` + fn process_config_update_log( + &mut self, + log: &Log, + rollup_config: &RollupConfig, + l1_time: u64, + ) -> Result<()> { + if log.topics().len() < 3 { + bail!("Invalid config update log: not enough topics"); + } + if log.topics()[0] != CONFIG_UPDATE_TOPIC { + bail!("Invalid config update log: invalid topic"); + } + + // Parse the config update log + let version = log.topics()[1]; + if version != CONFIG_UPDATE_EVENT_VERSION_0 { + bail!("Invalid config update log: unsupported version"); + } + let update_type = u64::from_be_bytes( + log.topics()[2].as_slice()[24..] + .try_into() + .map_err(|_| anyhow!("Failed to convert update type to u64"))?, + ); + let log_data = log.data.data.as_ref(); + + match update_type.try_into()? { + SystemConfigUpdateType::Batcher => { + if log_data.len() != 96 { + bail!("Invalid config update log: invalid data length"); + } + + let pointer = ::abi_decode(&log_data[0..32], true) + .map_err(|e| anyhow!("Failed to decode batcher update log"))?; + if pointer != 32 { + bail!("Invalid config update log: invalid data pointer"); + } + let length = ::abi_decode(&log_data[32..64], true) + .map_err(|e| anyhow!("Failed to decode batcher update log"))?; + if length != 32 { + bail!("Invalid config update log: invalid data length"); + } + + let batcher_address = + ::abi_decode(&log.data.data.as_ref()[64..], true) + .map_err(|e| anyhow!("Failed to decode batcher update log"))?; + self.batch_sender = batcher_address; + } + SystemConfigUpdateType::GasConfig => { + if log_data.len() != 128 { + bail!("Invalid config update log: invalid data length"); + } + + let pointer = ::abi_decode(&log_data[0..32], true) + .map_err(|e| anyhow!("Invalid config update log: invalid data pointer"))?; + if pointer != 32 { + bail!("Invalid config update log: invalid data pointer"); + } + let length = ::abi_decode(&log_data[32..64], true) + .map_err(|e| anyhow!("Invalid config update log: invalid data length"))?; + if length != 64 { + bail!("Invalid config update log: invalid data length"); + } + + let overhead = ::abi_decode(&log_data[64..96], true) + .map_err(|e| anyhow!("Invalid config update log: invalid overhead"))?; + let scalar = ::abi_decode(&log_data[96..], true) + .map_err(|e| anyhow!("Invalid config update log: invalid scalar"))?; + + if rollup_config.is_ecotone_active(l1_time) { + if RollupConfig::check_ecotone_l1_system_config_scalar(scalar.to_be_bytes()) + .is_err() + { + // ignore invalid scalars, retain the old system-config scalar + return Ok(()); + } + + // retain the scalar data in encoded form + self.l1_fee_scalar = scalar; + // zero out the overhead, it will not affect the state-transition after Ecotone + self.l1_fee_overhead = U256::ZERO; + } else { + self.l1_fee_scalar = scalar; + self.l1_fee_overhead = overhead; + } + } + SystemConfigUpdateType::GasLimit => { + if log_data.len() != 96 { + bail!("Invalid config update log: invalid data length"); + } + + let pointer = ::abi_decode(&log_data[0..32], true) + .map_err(|e| anyhow!("Invalid config update log: invalid data pointer"))?; + if pointer != 32 { + bail!("Invalid config update log: invalid data pointer"); + } + let length = ::abi_decode(&log_data[32..64], true) + .map_err(|e| anyhow!("Invalid config update log: invalid data length"))?; + if length != 32 { + bail!("Invalid config update log: invalid data length"); + } + + let gas_limit = ::abi_decode(&log_data[64..], true) + .map_err(|e| anyhow!("Invalid config update log: invalid gas limit"))?; + self.gas_limit = gas_limit; + } + SystemConfigUpdateType::UnsafeBlockSigner => { + // Ignored in derivation + } + } + + Ok(()) } } /// System accounts #[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SystemAccounts { /// The address that can deposit attributes pub attributes_depositor: Address, @@ -81,3 +224,160 @@ impl Default for SystemAccounts { } } } + +#[cfg(test)] +mod test { + use crate::types::Genesis; + + use super::*; + use alloc::vec; + use alloy_primitives::{hex, Bytes, LogData}; + + extern crate std; + + fn mock_rollup_config(system_config: SystemConfig) -> RollupConfig { + RollupConfig { + genesis: Genesis { + l1: crate::types::BlockId::Number(0), + l2: crate::types::BlockId::Number(0), + timestamp: 0, + system_config, + }, + block_time: 2, + max_sequencer_drift: 0, + seq_window_size: 0, + channel_timeout: 0, + l1_chain_id: 1, + l2_chain_id: 10, + regolith_time: Some(0), + canyon_time: Some(0), + delta_time: Some(0), + ecotone_time: Some(10), + fjord_time: Some(0), + interop_time: Some(0), + batch_inbox_address: Address::ZERO, + deposit_contract_address: Address::ZERO, + l1_system_config_address: Address::ZERO, + protocol_versions_address: Address::ZERO, + blobs_enabled_l1_timestamp: Some(0), + da_challenge_address: Some(Address::ZERO), + } + } + + #[test] + fn test_system_config_update_batcher_log() { + const UPDATE_TYPE: B256 = + b256!("0000000000000000000000000000000000000000000000000000000000000000"); + + let mut system_config = SystemConfig::default(); + let rollup_config = mock_rollup_config(system_config); + + let update_log = Log { + address: Address::ZERO, + data: LogData::new_unchecked( + vec![ + CONFIG_UPDATE_TOPIC, + CONFIG_UPDATE_EVENT_VERSION_0, + UPDATE_TYPE, + ], + hex!("00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000beef").into() + ) + }; + + // Update the batcher address. + system_config + .process_config_update_log(&update_log, &rollup_config, 0) + .unwrap(); + + assert_eq!( + system_config.batch_sender, + address!("000000000000000000000000000000000000bEEF") + ); + } + + #[test] + fn test_system_config_update_gas_config_log() { + const UPDATE_TYPE: B256 = + b256!("0000000000000000000000000000000000000000000000000000000000000001"); + + let mut system_config = SystemConfig::default(); + let rollup_config = mock_rollup_config(system_config); + + let update_log = Log { + address: Address::ZERO, + data: LogData::new_unchecked( + vec![ + CONFIG_UPDATE_TOPIC, + CONFIG_UPDATE_EVENT_VERSION_0, + UPDATE_TYPE, + ], + hex!("00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000babe000000000000000000000000000000000000000000000000000000000000beef").into() + ) + }; + + // Update the batcher address. + system_config + .process_config_update_log(&update_log, &rollup_config, 0) + .unwrap(); + + assert_eq!(system_config.l1_fee_overhead, U256::from(0xbabe)); + assert_eq!(system_config.l1_fee_scalar, U256::from(0xbeef)); + } + + #[test] + fn test_system_config_update_gas_config_log_ecotone() { + const UPDATE_TYPE: B256 = + b256!("0000000000000000000000000000000000000000000000000000000000000001"); + + let mut system_config = SystemConfig::default(); + let rollup_config = mock_rollup_config(system_config); + + let update_log = Log { + address: Address::ZERO, + data: LogData::new_unchecked( + vec![ + CONFIG_UPDATE_TOPIC, + CONFIG_UPDATE_EVENT_VERSION_0, + UPDATE_TYPE, + ], + hex!("00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000babe000000000000000000000000000000000000000000000000000000000000beef").into() + ) + }; + + // Update the batcher address. + system_config + .process_config_update_log(&update_log, &rollup_config, 10) + .unwrap(); + + assert_eq!(system_config.l1_fee_overhead, U256::from(0)); + assert_eq!(system_config.l1_fee_scalar, U256::from(0xbeef)); + } + + #[test] + fn test_system_config_update_gas_limit_log() { + const UPDATE_TYPE: B256 = + b256!("0000000000000000000000000000000000000000000000000000000000000002"); + + let mut system_config = SystemConfig::default(); + let rollup_config = mock_rollup_config(system_config); + + let update_log = Log { + address: Address::ZERO, + data: LogData::new_unchecked( + vec![ + CONFIG_UPDATE_TOPIC, + CONFIG_UPDATE_EVENT_VERSION_0, + UPDATE_TYPE, + ], + hex!("00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000beef").into() + ) + }; + + // Update the batcher address. + system_config + .process_config_update_log(&update_log, &rollup_config, 0) + .unwrap(); + + assert_eq!(system_config.gas_limit, U256::from(0xbeef)); + } +} diff --git a/crates/derive/src/types/eips/deposit.rs b/crates/derive/src/types/transaction/deposit.rs similarity index 100% rename from crates/derive/src/types/eips/deposit.rs rename to crates/derive/src/types/transaction/deposit.rs diff --git a/crates/derive/src/types/transaction/envelope.rs b/crates/derive/src/types/transaction/envelope.rs index 023ad066..c74bef8e 100644 --- a/crates/derive/src/types/transaction/envelope.rs +++ b/crates/derive/src/types/transaction/envelope.rs @@ -1,10 +1,7 @@ use crate::types::{ - eips::{ - deposit::TxDeposit, - eip2718::{Decodable2718, Eip2718Error, Encodable2718}, - }, + eips::eip2718::{Decodable2718, Eip2718Error, Encodable2718}, network::Signed, - transaction::{TxEip1559, TxEip2930, TxEip4844, TxLegacy}, + transaction::{TxDeposit, TxEip1559, TxEip2930, TxEip4844, TxLegacy}, }; use alloy_rlp::{length_of_length, Decodable, Encodable}; diff --git a/crates/derive/src/types/transaction/mod.rs b/crates/derive/src/types/transaction/mod.rs index 5b782d82..c8347c60 100644 --- a/crates/derive/src/types/transaction/mod.rs +++ b/crates/derive/src/types/transaction/mod.rs @@ -10,5 +10,8 @@ pub use legacy::TxLegacy; mod eip4844; pub use eip4844::TxEip4844; +mod deposit; +pub use deposit::TxDeposit; + mod envelope; pub use envelope::{TxEnvelope, TxType};