From a9c18aea9a8765661519cb41e1b92979dfa49f40 Mon Sep 17 00:00:00 2001 From: clabby Date: Fri, 19 Apr 2024 04:02:21 -0400 Subject: [PATCH] feat(derive): Use `L2ChainProvider` for system config fetching in attributes builder Reuses the `L2ChainProvider` for fetching the `SystemConfig` at a given block, rather than having an exlusive trait that extends the `L2ChainProvider`. Fix tests --- crates/derive/src/online/alloy_providers.rs | 21 ++- crates/derive/src/sources/factory.rs | 2 +- crates/derive/src/stages/attributes_queue.rs | 2 +- .../src/stages/attributes_queue/builder.rs | 125 ++++++++++-------- crates/derive/src/stages/mod.rs | 1 - .../stages/test_utils/sys_config_fetcher.rs | 40 ++++-- crates/derive/src/traits/data_sources.rs | 12 +- .../src/traits/test_utils/data_sources.rs | 26 +++- crates/derive/src/types/l1_block_info.rs | 20 ++- crates/derive/src/types/payload.rs | 59 ++++++++- crates/derive/src/types/rollup_config.rs | 5 - crates/derive/src/types/system_config.rs | 2 - 12 files changed, 226 insertions(+), 89 deletions(-) diff --git a/crates/derive/src/online/alloy_providers.rs b/crates/derive/src/online/alloy_providers.rs index 75e11b7b64..ce7b11ddcf 100644 --- a/crates/derive/src/online/alloy_providers.rs +++ b/crates/derive/src/online/alloy_providers.rs @@ -3,7 +3,10 @@ use crate::{ traits::{ChainProvider, L2ChainProvider}, - types::{Block, BlockInfo, L2BlockInfo, L2ExecutionPayloadEnvelope, OpBlock, RollupConfig}, + types::{ + Block, BlockInfo, L2BlockInfo, L2ExecutionPayloadEnvelope, OpBlock, RollupConfig, + SystemConfig, + }, }; use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloy_consensus::{Header, Receipt, ReceiptWithBloom, TxEnvelope, TxType}; @@ -165,6 +168,8 @@ pub struct AlloyL2ChainProvider>> { payload_by_number_cache: LruCache, /// `l2_block_info_by_number` LRU cache. l2_block_info_by_number_cache: LruCache, + /// `system_config_by_l2_hash` LRU cache. + system_config_by_number_cache: LruCache, } impl>> AlloyL2ChainProvider { @@ -175,6 +180,7 @@ impl>> AlloyL2ChainProvider { rollup_config, payload_by_number_cache: LruCache::new(NonZeroUsize::new(CACHE_SIZE).unwrap()), l2_block_info_by_number_cache: LruCache::new(NonZeroUsize::new(CACHE_SIZE).unwrap()), + system_config_by_number_cache: LruCache::new(NonZeroUsize::new(CACHE_SIZE).unwrap()), } } } @@ -209,4 +215,17 @@ impl>> L2ChainProvider for AlloyL2ChainProvide self.payload_by_number_cache.put(number, payload_envelope.clone()); Ok(payload_envelope) } + + async fn system_config_by_number( + &mut self, + number: u64, + rollup_config: Arc, + ) -> Result { + if let Some(system_config) = self.system_config_by_number_cache.get(&number) { + return Ok(*system_config); + } + + let envelope = self.payload_by_number(number).await?; + envelope.to_system_config(&rollup_config) + } } diff --git a/crates/derive/src/sources/factory.rs b/crates/derive/src/sources/factory.rs index 231d42c2e5..1d39d4b275 100644 --- a/crates/derive/src/sources/factory.rs +++ b/crates/derive/src/sources/factory.rs @@ -41,7 +41,7 @@ where blob_provider: blobs, ecotone_timestamp: cfg.ecotone_time, plasma_enabled: cfg.is_plasma_enabled(), - signer: cfg.l1_signer_address(), + signer: cfg.genesis.system_config.batcher_addr, } } } diff --git a/crates/derive/src/stages/attributes_queue.rs b/crates/derive/src/stages/attributes_queue.rs index fe549fae7a..98383de83b 100644 --- a/crates/derive/src/stages/attributes_queue.rs +++ b/crates/derive/src/stages/attributes_queue.rs @@ -16,7 +16,7 @@ mod deposits; pub(crate) use deposits::derive_deposits; mod builder; -pub use builder::{AttributesBuilder, StatefulAttributesBuilder, SystemConfigL2Fetcher}; +pub use builder::{AttributesBuilder, StatefulAttributesBuilder}; /// [AttributesProvider] is a trait abstraction that generalizes the [BatchQueue] stage. /// diff --git a/crates/derive/src/stages/attributes_queue/builder.rs b/crates/derive/src/stages/attributes_queue/builder.rs index ee0d9ac6e4..4282671da7 100644 --- a/crates/derive/src/stages/attributes_queue/builder.rs +++ b/crates/derive/src/stages/attributes_queue/builder.rs @@ -3,14 +3,13 @@ use super::derive_deposits; use crate::{ params::SEQUENCER_FEE_VAULT_ADDRESS, - traits::ChainProvider, + traits::{ChainProvider, L2ChainProvider}, types::{ BlockID, BuilderError, EcotoneTransactionBuilder, L1BlockInfoTx, L2BlockInfo, - L2PayloadAttributes, RawTransaction, RollupConfig, SystemConfig, + L2PayloadAttributes, RawTransaction, RollupConfig, }, }; use alloc::{boxed::Box, fmt::Debug, sync::Arc, vec, vec::Vec}; -use alloy_primitives::B256; use alloy_rlp::Encodable; use async_trait::async_trait; @@ -32,43 +31,37 @@ pub trait AttributesBuilder { ) -> Result; } -/// The [SystemConfigL2Fetcher] fetches the system config by L2 hash. -pub trait SystemConfigL2Fetcher { - /// Fetch the system config by L2 hash. - fn system_config_by_l2_hash(&self, hash: B256) -> anyhow::Result; -} - /// A stateful implementation of the [AttributesBuilder]. #[derive(Debug, Default)] -pub struct StatefulAttributesBuilder +pub struct StatefulAttributesBuilder where - S: SystemConfigL2Fetcher + Debug, - R: ChainProvider + Debug, + L1P: ChainProvider + Debug, + L2P: L2ChainProvider + Debug, { /// The rollup config. rollup_cfg: Arc, /// The system config fetcher. - config_fetcher: S, + config_fetcher: L2P, /// The L1 receipts fetcher. - receipts_fetcher: R, + receipts_fetcher: L1P, } -impl StatefulAttributesBuilder +impl StatefulAttributesBuilder where - S: SystemConfigL2Fetcher + Debug, - R: ChainProvider + Debug, + L1P: ChainProvider + Debug, + L2P: L2ChainProvider + Debug, { /// Create a new [StatefulAttributesBuilder] with the given epoch. - pub fn new(rcfg: Arc, cfg: S, receipts: R) -> Self { - Self { rollup_cfg: rcfg, config_fetcher: cfg, receipts_fetcher: receipts } + pub fn new(rcfg: Arc, sys_cfg_fetcher: L2P, receipts: L1P) -> Self { + Self { rollup_cfg: rcfg, config_fetcher: sys_cfg_fetcher, receipts_fetcher: receipts } } } #[async_trait] -impl AttributesBuilder for StatefulAttributesBuilder +impl AttributesBuilder for StatefulAttributesBuilder where - S: SystemConfigL2Fetcher + Send + Debug, - R: ChainProvider + Send + Debug, + L1P: ChainProvider + Debug + Send, + L2P: L2ChainProvider + Debug + Send, { async fn prepare_payload_attributes( &mut self, @@ -77,8 +70,10 @@ where ) -> Result { let l1_header; let deposit_transactions: Vec; - let mut sys_config = - self.config_fetcher.system_config_by_l2_hash(l2_parent.block_info.hash)?; + let mut sys_config = self + .config_fetcher + .system_config_by_number(l2_parent.block_info.number, self.rollup_cfg.clone()) + .await?; // If the L1 origin changed in this block, then we are in the first block of the epoch. // In this case we need to fetch all transaction receipts from the L1 origin block so @@ -177,27 +172,28 @@ where mod tests { use super::*; use crate::{ - stages::test_utils::MockSystemConfigL2Fetcher, traits::test_utils::TestChainProvider, - types::BlockInfo, + stages::test_utils::MockSystemConfigL2Fetcher, + traits::test_utils::TestChainProvider, + types::{BlockInfo, SystemConfig}, }; use alloy_consensus::Header; - use alloy_primitives::b256; + use alloy_primitives::B256; #[tokio::test] async fn test_prepare_payload_block_mismatch_epoch_reset() { let cfg = Arc::new(RollupConfig::default()); - let l2_hash = b256!("0000000000000000000000000000000000000000000000000000000000000002"); + let l2_number = 1; let mut fetcher = MockSystemConfigL2Fetcher::default(); - fetcher.insert(l2_hash, SystemConfig::default()); + fetcher.insert(l2_number, SystemConfig::default()); let mut provider = TestChainProvider::default(); let header = Header::default(); let hash = header.hash_slow(); provider.insert_header(hash, header); let mut builder = StatefulAttributesBuilder::new(cfg, fetcher, provider); - let epoch = BlockID { hash, number: 1 }; + let epoch = BlockID { hash, number: l2_number }; let l2_parent = L2BlockInfo { - block_info: BlockInfo { hash: l2_hash, number: 1, ..Default::default() }, - l1_origin: BlockID { hash: l2_hash, number: 2 }, + block_info: BlockInfo { hash: B256::ZERO, number: l2_number, ..Default::default() }, + l1_origin: BlockID { hash: B256::left_padding_from(&[0xFF]), number: 2 }, seq_num: 0, }; // This should error because the l2 parent's l1_origin.hash should equal the epoch header @@ -211,18 +207,18 @@ mod tests { #[tokio::test] async fn test_prepare_payload_block_mismatch() { let cfg = Arc::new(RollupConfig::default()); - let l2_hash = b256!("0000000000000000000000000000000000000000000000000000000000000002"); + let l2_number = 1; let mut fetcher = MockSystemConfigL2Fetcher::default(); - fetcher.insert(l2_hash, SystemConfig::default()); + fetcher.insert(l2_number, SystemConfig::default()); let mut provider = TestChainProvider::default(); let header = Header::default(); let hash = header.hash_slow(); provider.insert_header(hash, header); let mut builder = StatefulAttributesBuilder::new(cfg, fetcher, provider); - let epoch = BlockID { hash, number: 1 }; + let epoch = BlockID { hash, number: l2_number }; let l2_parent = L2BlockInfo { - block_info: BlockInfo { hash: l2_hash, number: 1, ..Default::default() }, - l1_origin: BlockID { hash: l2_hash, number: 1 }, + block_info: BlockInfo { hash: B256::ZERO, number: l2_number, ..Default::default() }, + l1_origin: BlockID { hash: B256::ZERO, number: l2_number }, seq_num: 0, }; // This should error because the l2 parent's l1_origin.hash should equal the epoch hash @@ -237,18 +233,18 @@ mod tests { let block_time = 10; let timestamp = 100; let cfg = Arc::new(RollupConfig { block_time, ..Default::default() }); - let l2_hash = b256!("0000000000000000000000000000000000000000000000000000000000000002"); + let l2_number = 1; let mut fetcher = MockSystemConfigL2Fetcher::default(); - fetcher.insert(l2_hash, SystemConfig::default()); + fetcher.insert(l2_number, SystemConfig::default()); let mut provider = TestChainProvider::default(); let header = Header { timestamp, ..Default::default() }; let hash = header.hash_slow(); provider.insert_header(hash, header); let mut builder = StatefulAttributesBuilder::new(cfg, fetcher, provider); - let epoch = BlockID { hash, number: 1 }; + let epoch = BlockID { hash, number: l2_number }; let l2_parent = L2BlockInfo { - block_info: BlockInfo { hash: l2_hash, number: 1, ..Default::default() }, - l1_origin: BlockID { hash, number: 1 }, + block_info: BlockInfo { hash: B256::ZERO, number: l2_number, ..Default::default() }, + l1_origin: BlockID { hash, number: l2_number }, seq_num: 0, }; let next_l2_time = l2_parent.block_info.timestamp + block_time; @@ -268,19 +264,24 @@ mod tests { let block_time = 10; let timestamp = 100; let cfg = Arc::new(RollupConfig { block_time, ..Default::default() }); - let l2_hash = b256!("0000000000000000000000000000000000000000000000000000000000000002"); + let l2_number = 1; let mut fetcher = MockSystemConfigL2Fetcher::default(); - fetcher.insert(l2_hash, SystemConfig::default()); + fetcher.insert(l2_number, SystemConfig::default()); let mut provider = TestChainProvider::default(); let header = Header { timestamp, ..Default::default() }; let prev_randao = header.mix_hash; let hash = header.hash_slow(); provider.insert_header(hash, header); let mut builder = StatefulAttributesBuilder::new(cfg, fetcher, provider); - let epoch = BlockID { hash, number: 1 }; + let epoch = BlockID { hash, number: l2_number }; let l2_parent = L2BlockInfo { - block_info: BlockInfo { hash: l2_hash, number: 1, timestamp, parent_hash: hash }, - l1_origin: BlockID { hash, number: 1 }, + block_info: BlockInfo { + hash: B256::ZERO, + number: l2_number, + timestamp, + parent_hash: hash, + }, + l1_origin: BlockID { hash, number: l2_number }, seq_num: 0, }; let next_l2_time = l2_parent.block_info.timestamp + block_time; @@ -306,19 +307,24 @@ mod tests { let block_time = 10; let timestamp = 100; let cfg = Arc::new(RollupConfig { block_time, canyon_time: Some(0), ..Default::default() }); - let l2_hash = b256!("0000000000000000000000000000000000000000000000000000000000000002"); + let l2_number = 1; let mut fetcher = MockSystemConfigL2Fetcher::default(); - fetcher.insert(l2_hash, SystemConfig::default()); + fetcher.insert(l2_number, SystemConfig::default()); let mut provider = TestChainProvider::default(); let header = Header { timestamp, ..Default::default() }; let prev_randao = header.mix_hash; let hash = header.hash_slow(); provider.insert_header(hash, header); let mut builder = StatefulAttributesBuilder::new(cfg, fetcher, provider); - let epoch = BlockID { hash, number: 1 }; + let epoch = BlockID { hash, number: l2_number }; let l2_parent = L2BlockInfo { - block_info: BlockInfo { hash: l2_hash, number: 1, timestamp, parent_hash: hash }, - l1_origin: BlockID { hash, number: 1 }, + block_info: BlockInfo { + hash: B256::ZERO, + number: l2_number, + timestamp, + parent_hash: hash, + }, + l1_origin: BlockID { hash, number: l2_number }, seq_num: 0, }; let next_l2_time = l2_parent.block_info.timestamp + block_time; @@ -345,9 +351,9 @@ mod tests { let timestamp = 100; let cfg = Arc::new(RollupConfig { block_time, ecotone_time: Some(0), ..Default::default() }); - let l2_hash = b256!("0000000000000000000000000000000000000000000000000000000000000002"); + let l2_number = 1; let mut fetcher = MockSystemConfigL2Fetcher::default(); - fetcher.insert(l2_hash, SystemConfig::default()); + fetcher.insert(l2_number, SystemConfig::default()); let mut provider = TestChainProvider::default(); let header = Header { timestamp, ..Default::default() }; let parent_beacon_block_root = Some(header.parent_beacon_block_root.unwrap_or_default()); @@ -355,10 +361,15 @@ mod tests { let hash = header.hash_slow(); provider.insert_header(hash, header); let mut builder = StatefulAttributesBuilder::new(cfg, fetcher, provider); - let epoch = BlockID { hash, number: 1 }; + let epoch = BlockID { hash, number: l2_number }; let l2_parent = L2BlockInfo { - block_info: BlockInfo { hash: l2_hash, number: 1, timestamp, parent_hash: hash }, - l1_origin: BlockID { hash, number: 1 }, + block_info: BlockInfo { + hash: B256::ZERO, + number: l2_number, + timestamp, + parent_hash: hash, + }, + l1_origin: BlockID { hash, number: l2_number }, seq_num: 0, }; let next_l2_time = l2_parent.block_info.timestamp + block_time; diff --git a/crates/derive/src/stages/mod.rs b/crates/derive/src/stages/mod.rs index 9517d34352..a428572e7c 100644 --- a/crates/derive/src/stages/mod.rs +++ b/crates/derive/src/stages/mod.rs @@ -34,7 +34,6 @@ pub use batch_queue::{BatchQueue, BatchQueueProvider}; mod attributes_queue; pub use attributes_queue::{ AttributesBuilder, AttributesProvider, AttributesQueue, StatefulAttributesBuilder, - SystemConfigL2Fetcher, }; #[cfg(test)] diff --git a/crates/derive/src/stages/test_utils/sys_config_fetcher.rs b/crates/derive/src/stages/test_utils/sys_config_fetcher.rs index 2a34ff691e..53489faa9d 100644 --- a/crates/derive/src/stages/test_utils/sys_config_fetcher.rs +++ b/crates/derive/src/stages/test_utils/sys_config_fetcher.rs @@ -1,20 +1,25 @@ //! Implements a mock [L2SystemConfigFetcher] for testing. -use crate::{stages::attributes_queue::SystemConfigL2Fetcher, types::SystemConfig}; -use alloy_primitives::B256; +use crate::{ + traits::L2ChainProvider, + types::{L2BlockInfo, L2ExecutionPayloadEnvelope, RollupConfig, SystemConfig}, +}; +use alloc::{boxed::Box, sync::Arc}; +use anyhow::Result; +use async_trait::async_trait; use hashbrown::HashMap; /// A mock implementation of the [`SystemConfigL2Fetcher`] for testing. #[derive(Debug, Default)] pub struct MockSystemConfigL2Fetcher { - /// A map from [B256] block hash to a [SystemConfig]. - pub system_configs: HashMap, + /// A map from [u64] block number to a [SystemConfig]. + pub system_configs: HashMap, } impl MockSystemConfigL2Fetcher { - /// Inserts a new system config into the mock fetcher with the given hash. - pub fn insert(&mut self, hash: B256, config: SystemConfig) { - self.system_configs.insert(hash, config); + /// Inserts a new system config into the mock fetcher with the given block number. + pub fn insert(&mut self, number: u64, config: SystemConfig) { + self.system_configs.insert(number, config); } /// Clears all system configs from the mock fetcher. @@ -23,11 +28,24 @@ impl MockSystemConfigL2Fetcher { } } -impl SystemConfigL2Fetcher for MockSystemConfigL2Fetcher { - fn system_config_by_l2_hash(&self, hash: B256) -> anyhow::Result { +#[async_trait] +impl L2ChainProvider for MockSystemConfigL2Fetcher { + async fn system_config_by_number( + &mut self, + number: u64, + _: Arc, + ) -> Result { self.system_configs - .get(&hash) + .get(&number) .cloned() - .ok_or_else(|| anyhow::anyhow!("system config not found")) + .ok_or_else(|| anyhow::anyhow!("system config not found: {number}")) + } + + async fn l2_block_info_by_number(&mut self, _: u64) -> Result { + unimplemented!() + } + + async fn payload_by_number(&mut self, _: u64) -> Result { + unimplemented!() } } diff --git a/crates/derive/src/traits/data_sources.rs b/crates/derive/src/traits/data_sources.rs index 6c61b0b22a..1061b84ea1 100644 --- a/crates/derive/src/traits/data_sources.rs +++ b/crates/derive/src/traits/data_sources.rs @@ -2,9 +2,10 @@ //! pipeline's stages. use crate::types::{ - Blob, BlockInfo, IndexedBlobHash, L2BlockInfo, L2ExecutionPayloadEnvelope, StageResult, + Blob, BlockInfo, IndexedBlobHash, L2BlockInfo, L2ExecutionPayloadEnvelope, RollupConfig, + StageResult, SystemConfig, }; -use alloc::{boxed::Box, fmt::Debug, vec::Vec}; +use alloc::{boxed::Box, fmt::Debug, sync::Arc, vec::Vec}; use alloy_consensus::{Header, Receipt, TxEnvelope}; use alloy_primitives::{Address, Bytes, B256}; use anyhow::Result; @@ -41,6 +42,13 @@ pub trait L2ChainProvider { /// Returns an execution payload for a given number. /// Errors if the execution payload does not exist. async fn payload_by_number(&mut self, number: u64) -> Result; + + /// Returns the [SystemConfig] by L2 number. + async fn system_config_by_number( + &mut self, + number: u64, + rollup_config: Arc, + ) -> Result; } /// The BlobProvider trait specifies the functionality of a data source that can provide blobs. diff --git a/crates/derive/src/traits/test_utils/data_sources.rs b/crates/derive/src/traits/test_utils/data_sources.rs index ae122c5687..1fb473f3e8 100644 --- a/crates/derive/src/traits/test_utils/data_sources.rs +++ b/crates/derive/src/traits/test_utils/data_sources.rs @@ -2,13 +2,14 @@ use crate::{ traits::{ChainProvider, L2ChainProvider}, - types::{BlockInfo, L2BlockInfo, L2ExecutionPayloadEnvelope}, + types::{BlockInfo, L2BlockInfo, L2ExecutionPayloadEnvelope, RollupConfig, SystemConfig}, }; -use alloc::{boxed::Box, vec::Vec}; +use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloy_consensus::{Header, Receipt, TxEnvelope}; use alloy_primitives::B256; use anyhow::Result; use async_trait::async_trait; +use hashbrown::HashMap; /// A mock block fetcher. #[derive(Debug, Default)] @@ -17,12 +18,18 @@ pub struct MockBlockFetcher { pub blocks: Vec, /// Payloads pub payloads: Vec, + /// System configs + pub system_configs: HashMap, } impl MockBlockFetcher { /// Creates a new [MockBlockFetcher] with the given origin and batches. - pub fn new(blocks: Vec, payloads: Vec) -> Self { - Self { blocks, payloads } + pub fn new( + blocks: Vec, + payloads: Vec, + system_configs: HashMap, + ) -> Self { + Self { blocks, payloads, system_configs } } } @@ -43,6 +50,17 @@ impl L2ChainProvider for MockBlockFetcher { .cloned() .ok_or_else(|| anyhow::anyhow!("Payload not found")) } + + async fn system_config_by_number( + &mut self, + number: u64, + _: Arc, + ) -> Result { + self.system_configs + .get(&number) + .ok_or_else(|| anyhow::anyhow!("System config not found")) + .cloned() + } } /// A mock chain provider for testing. diff --git a/crates/derive/src/types/l1_block_info.rs b/crates/derive/src/types/l1_block_info.rs index 11f3d9386d..053f7117eb 100644 --- a/crates/derive/src/types/l1_block_info.rs +++ b/crates/derive/src/types/l1_block_info.rs @@ -226,8 +226,8 @@ impl L1BlockInfoTx { /// Encodes the [L1BlockInfoTx] object into Ethereum transaction calldata. pub fn encode_calldata(&self) -> Bytes { match self { - Self::Ecotone(ecotone_tx) => ecotone_tx.encode_calldata(), Self::Bedrock(bedrock_tx) => bedrock_tx.encode_calldata(), + Self::Ecotone(ecotone_tx) => ecotone_tx.encode_calldata(), } } @@ -243,11 +243,27 @@ impl L1BlockInfoTx { } } + /// Returns the L1 fee overhead for the info transaction. After ecotone, this value is ignored. + pub fn l1_fee_overhead(&self) -> U256 { + match self { + Self::Bedrock(L1BlockInfoBedrock { l1_fee_overhead, .. }) => *l1_fee_overhead, + Self::Ecotone(_) => U256::ZERO, + } + } + + /// Returns the batcher address for the info transaction + pub fn batcher_address(&self) -> Address { + match self { + Self::Bedrock(L1BlockInfoBedrock { batcher_address, .. }) => *batcher_address, + Self::Ecotone(L1BlockInfoEcotone { batcher_address, .. }) => *batcher_address, + } + } + /// Returns the sequence number for the info transaction pub fn sequence_number(&self) -> u64 { match self { - Self::Ecotone(L1BlockInfoEcotone { sequence_number, .. }) => *sequence_number, Self::Bedrock(L1BlockInfoBedrock { sequence_number, .. }) => *sequence_number, + Self::Ecotone(L1BlockInfoEcotone { sequence_number, .. }) => *sequence_number, } } } diff --git a/crates/derive/src/types/payload.rs b/crates/derive/src/types/payload.rs index 6e762a95aa..347646f673 100644 --- a/crates/derive/src/types/payload.rs +++ b/crates/derive/src/types/payload.rs @@ -1,7 +1,7 @@ //! Contains the execution payload type. use alloc::vec::Vec; -use alloy_primitives::{Address, Bloom, Bytes, B256}; +use alloy_primitives::{Address, Bloom, Bytes, B256, U256}; use anyhow::Result; use op_alloy_consensus::OpTxEnvelope; @@ -13,7 +13,11 @@ pub const PAYLOAD_MEM_FIXED_COST: u64 = 1000; /// 24 bytes per tx overhead (size of slice header in memory). pub const PAYLOAD_TX_MEM_OVERHEAD: u64 = 24; -use super::{Block, BlockInfo, L1BlockInfoTx, L2BlockInfo, OpBlock, RollupConfig, Withdrawal}; +use crate::types::{L1BlockInfoBedrock, L1BlockInfoEcotone}; + +use super::{ + Block, BlockInfo, L1BlockInfoTx, L2BlockInfo, OpBlock, RollupConfig, SystemConfig, Withdrawal, +}; use alloy_rlp::{Decodable, Encodable}; #[cfg(feature = "serde")] @@ -153,6 +157,57 @@ impl L2ExecutionPayloadEnvelope { seq_num: sequence_number, }) } + + /// Converts the [L2ExecutionPayloadEnvelope] to a partial [SystemConfig]. + pub fn to_system_config(&self, rollup_config: &RollupConfig) -> Result { + let L2ExecutionPayloadEnvelope { execution_payload, .. } = self; + + if execution_payload.block_number == rollup_config.genesis.l2.number { + if execution_payload.block_hash != rollup_config.genesis.l2.hash { + anyhow::bail!("Invalid genesis hash"); + } + return Ok(rollup_config.genesis.system_config); + } + + if execution_payload.transactions.is_empty() { + anyhow::bail!( + "L2 block is missing L1 info deposit transaction, block hash: {}", + execution_payload.block_hash + ); + } + let tx = OpTxEnvelope::decode(&mut execution_payload.transactions[0].as_ref()) + .map_err(|e| anyhow::anyhow!(e))?; + + let OpTxEnvelope::Deposit(tx) = tx else { + anyhow::bail!("First payload transaction has unexpected type: {:?}", tx.tx_type()); + }; + + 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 { + blob_base_fee, + 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(blob_base_fee.to_be_bytes().as_ref()); + buf.into() + } + }; + + Ok(SystemConfig { + batcher_addr: l1_info.batcher_address(), + l1_fee_overhead: l1_info.l1_fee_overhead(), + l1_fee_scalar, + gas_limit: U256::from(execution_payload.gas_limit), + }) + } } impl From for L2ExecutionPayloadEnvelope { diff --git a/crates/derive/src/types/rollup_config.rs b/crates/derive/src/types/rollup_config.rs index 751f4413d6..c27739f73c 100644 --- a/crates/derive/src/types/rollup_config.rs +++ b/crates/derive/src/types/rollup_config.rs @@ -84,11 +84,6 @@ impl RollupConfig { self.regolith_time.map_or(false, |t| timestamp >= t) } - /// Returns the L1 Signer Address. - pub fn l1_signer_address(&self) -> Address { - self.genesis.system_config.unsafe_block_signer - } - /// 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) diff --git a/crates/derive/src/types/system_config.rs b/crates/derive/src/types/system_config.rs index 7a3d836311..2f5391fe81 100644 --- a/crates/derive/src/types/system_config.rs +++ b/crates/derive/src/types/system_config.rs @@ -22,8 +22,6 @@ pub struct SystemConfig { /// Fee scalar #[cfg_attr(feature = "serde", serde(rename = "scalar"))] pub l1_fee_scalar: U256, - /// Sequencer's signer for unsafe blocks - pub unsafe_block_signer: Address, } /// Represents type of update to the system config.