kona_derive/sources/
ethereum.rs1use crate::{
5 BlobProvider, BlobSource, CalldataSource, ChainProvider, DataAvailabilityProvider,
6 PipelineResult,
7};
8use alloc::{boxed::Box, fmt::Debug};
9use alloy_primitives::{Address, Bytes};
10use async_trait::async_trait;
11use kona_genesis::RollupConfig;
12use kona_protocol::BlockInfo;
13
14#[derive(Debug, Clone)]
16pub struct EthereumDataSource<C, B>
17where
18 C: ChainProvider + Send + Clone,
19 B: BlobProvider + Send + Clone,
20{
21 pub ecotone_timestamp: Option<u64>,
23 pub blob_source: BlobSource<C, B>,
25 pub calldata_source: CalldataSource<C>,
27}
28
29impl<C, B> EthereumDataSource<C, B>
30where
31 C: ChainProvider + Send + Clone + Debug,
32 B: BlobProvider + Send + Clone + Debug,
33{
34 pub const fn new(
36 blob_source: BlobSource<C, B>,
37 calldata_source: CalldataSource<C>,
38 cfg: &RollupConfig,
39 ) -> Self {
40 Self { ecotone_timestamp: cfg.hardforks.ecotone_time, blob_source, calldata_source }
41 }
42
43 pub fn new_from_parts(provider: C, blobs: B, cfg: &RollupConfig) -> Self {
45 Self {
46 ecotone_timestamp: cfg.hardforks.ecotone_time,
47 blob_source: BlobSource::new(provider.clone(), blobs, cfg.batch_inbox_address),
48 calldata_source: CalldataSource::new(provider, cfg.batch_inbox_address),
49 }
50 }
51}
52
53#[async_trait]
54impl<C, B> DataAvailabilityProvider for EthereumDataSource<C, B>
55where
56 C: ChainProvider + Send + Sync + Clone + Debug,
57 B: BlobProvider + Send + Sync + Clone + Debug,
58{
59 type Item = Bytes;
60
61 async fn next(
62 &mut self,
63 block_ref: &BlockInfo,
64 batcher_address: Address,
65 ) -> PipelineResult<Self::Item> {
66 let ecotone_enabled =
67 self.ecotone_timestamp.map(|e| block_ref.timestamp >= e).unwrap_or(false);
68 if ecotone_enabled {
69 self.blob_source.next(block_ref, batcher_address).await
70 } else {
71 self.calldata_source.next(block_ref, batcher_address).await
72 }
73 }
74
75 fn clear(&mut self) {
76 self.blob_source.clear();
77 self.calldata_source.clear();
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use crate::{
85 BlobData,
86 test_utils::{TestBlobProvider, TestChainProvider},
87 };
88 use alloc::vec;
89 use alloy_consensus::TxEnvelope;
90 use alloy_eips::eip2718::Decodable2718;
91 use alloy_primitives::{Address, address};
92 use kona_genesis::{HardForkConfig, RollupConfig, SystemConfig};
93 use kona_protocol::BlockInfo;
94
95 fn default_test_blob_source() -> BlobSource<TestChainProvider, TestBlobProvider> {
96 let chain_provider = TestChainProvider::default();
97 let blob_fetcher = TestBlobProvider::default();
98 let batcher_address = Address::default();
99 BlobSource::new(chain_provider, blob_fetcher, batcher_address)
100 }
101
102 #[tokio::test]
103 async fn test_clear_ethereum_data_source() {
104 let chain = TestChainProvider::default();
105 let blob = TestBlobProvider::default();
106 let cfg = RollupConfig::default();
107 let mut calldata = CalldataSource::new(chain.clone(), Address::ZERO);
108 calldata.calldata.insert(0, Default::default());
109 calldata.open = true;
110 let mut blob = BlobSource::new(chain, blob, Address::ZERO);
111 blob.data = vec![Default::default()];
112 blob.open = true;
113 let mut data_source = EthereumDataSource::new(blob, calldata, &cfg);
114
115 data_source.clear();
116 assert!(data_source.blob_source.data.is_empty());
117 assert!(!data_source.blob_source.open);
118 assert!(data_source.calldata_source.calldata.is_empty());
119 assert!(!data_source.calldata_source.open);
120 }
121
122 #[tokio::test]
123 async fn test_open_blob_source() {
124 let chain = TestChainProvider::default();
125 let mut blob = default_test_blob_source();
126 blob.open = true;
127 blob.data.push(BlobData { data: None, calldata: Some(Bytes::default()) });
128 let calldata = CalldataSource::new(chain.clone(), Address::ZERO);
129 let cfg = RollupConfig {
130 hardforks: HardForkConfig { ecotone_time: Some(0), ..Default::default() },
131 ..Default::default()
132 };
133
134 let mut data_source = EthereumDataSource::new(blob, calldata, &cfg);
136 let data = data_source.next(&BlockInfo::default(), Address::ZERO).await.unwrap();
137 assert_eq!(data, Bytes::default());
138 }
139
140 #[tokio::test]
141 async fn test_open_ethereum_calldata_source_pre_ecotone() {
142 let mut chain = TestChainProvider::default();
143 let blob = TestBlobProvider::default();
144 let batcher_address = address!("6887246668a3b87F54DeB3b94Ba47a6f63F32985");
145 let batch_inbox = address!("FF00000000000000000000000000000000000010");
146 let block_ref = BlockInfo { number: 10, ..Default::default() };
147
148 let mut cfg = RollupConfig::default();
149 cfg.genesis.system_config = Some(SystemConfig { batcher_address, ..Default::default() });
150 cfg.batch_inbox_address = batch_inbox;
151
152 let raw_batcher_tx = include_bytes!("../../testdata/raw_batcher_tx.hex");
154 let tx = TxEnvelope::decode_2718(&mut raw_batcher_tx.as_ref()).unwrap();
155 chain.insert_block_with_transactions(10, block_ref, vec![tx]);
156
157 let mut data_source = EthereumDataSource::new_from_parts(chain, blob, &cfg);
159 let calldata_batch = data_source.next(&block_ref, batcher_address).await.unwrap();
160 assert_eq!(calldata_batch.len(), 119823);
161 }
162}