Skip to main content

ethrex_storage_rollup/
store.rs

1use std::{path::Path, sync::Arc};
2
3use crate::api::StoreEngineRollup;
4use crate::error::RollupStoreError;
5use crate::store_db::in_memory::Store as InMemoryStore;
6#[cfg(feature = "sql")]
7use crate::store_db::sql::SQLStore;
8use ethrex_common::{
9    H256,
10    types::{
11        AccountUpdate, Blob, BlobsBundle, BlockNumber, Fork, balance_diff::BalanceDiff,
12        batch::Batch, fee_config::FeeConfig,
13    },
14};
15use ethrex_l2_common::prover::{ProverInputData, ProverOutput, ProverType};
16use tracing::info;
17
18#[derive(Debug, Clone)]
19pub struct Store {
20    engine: Arc<dyn StoreEngineRollup>,
21}
22
23impl Default for Store {
24    fn default() -> Self {
25        Self {
26            engine: Arc::new(InMemoryStore::new()),
27        }
28    }
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum EngineType {
33    InMemory,
34    #[cfg(feature = "sql")]
35    SQL,
36}
37
38impl Store {
39    pub fn new(_path: &Path, engine_type: EngineType) -> Result<Self, RollupStoreError> {
40        info!("Starting l2 storage engine ({engine_type:?})");
41        let store = match engine_type {
42            EngineType::InMemory => Self {
43                engine: Arc::new(InMemoryStore::new()),
44            },
45            #[cfg(feature = "sql")]
46            EngineType::SQL => Self {
47                engine: Arc::new(SQLStore::new(_path)?),
48            },
49        };
50        info!("Started l2 store engine");
51        Ok(store)
52    }
53
54    pub async fn init(&self) -> Result<(), RollupStoreError> {
55        // Stores batch 0 with block 0
56        self.seal_batch(Batch {
57            number: 0,
58            first_block: 0,
59            last_block: 0,
60            state_root: H256::zero(),
61            l1_in_messages_rolling_hash: H256::zero(),
62            l2_in_message_rolling_hashes: Vec::new(),
63            l1_out_message_hashes: Vec::new(),
64            non_privileged_transactions: 0,
65            balance_diffs: Vec::new(),
66            blobs_bundle: BlobsBundle::empty(),
67            commit_tx: None,
68            verify_tx: None,
69        })
70        .await?;
71        // Sets the latest verified batch proof to 0
72        if self.get_latest_verified_batch_proof().await.is_err() {
73            self.set_latest_verified_batch_proof(0, 0).await?;
74        };
75        // Initialize the aligned cursor if not set
76        if self.get_latest_sent_to_aligned().await.is_err() {
77            self.set_latest_sent_to_aligned(0).await?;
78        };
79        Ok(())
80    }
81
82    /// Returns the block numbers by a given batch_number
83    pub async fn get_block_numbers_by_batch(
84        &self,
85        batch_number: u64,
86    ) -> Result<Option<Vec<BlockNumber>>, RollupStoreError> {
87        self.engine.get_block_numbers_by_batch(batch_number).await
88    }
89
90    pub async fn get_batch_number_by_block(
91        &self,
92        block_number: BlockNumber,
93    ) -> Result<Option<u64>, RollupStoreError> {
94        self.engine.get_batch_number_by_block(block_number).await
95    }
96
97    pub async fn get_l1_out_message_hashes_by_batch(
98        &self,
99        batch_number: u64,
100    ) -> Result<Option<Vec<H256>>, RollupStoreError> {
101        self.engine
102            .get_l1_out_message_hashes_by_batch(batch_number)
103            .await
104    }
105
106    pub async fn get_balance_diffs_by_batch(
107        &self,
108        batch_number: u64,
109    ) -> Result<Option<Vec<BalanceDiff>>, RollupStoreError> {
110        self.engine.get_balance_diffs_by_batch(batch_number).await
111    }
112
113    pub async fn get_l1_in_messages_rolling_hash_by_batch_number(
114        &self,
115        batch_number: u64,
116    ) -> Result<Option<H256>, RollupStoreError> {
117        self.engine
118            .get_l1_in_messages_rolling_hash_by_batch_number(batch_number)
119            .await
120    }
121
122    pub async fn get_l2_in_message_rolling_hashes_by_batch(
123        &self,
124        batch_number: u64,
125    ) -> Result<Option<Vec<(u64, H256)>>, RollupStoreError> {
126        self.engine
127            .get_l2_in_message_rolling_hashes_by_batch(batch_number)
128            .await
129    }
130
131    pub async fn get_state_root_by_batch(
132        &self,
133        batch_number: u64,
134    ) -> Result<Option<H256>, RollupStoreError> {
135        self.engine
136            .get_state_root_by_batch_number(batch_number)
137            .await
138    }
139
140    pub async fn get_blobs_by_batch(
141        &self,
142        batch_number: u64,
143    ) -> Result<Option<Vec<Blob>>, RollupStoreError> {
144        self.engine
145            .get_blob_bundle_by_batch_number(batch_number)
146            .await
147    }
148
149    pub async fn get_commit_tx_by_batch(
150        &self,
151        batch_number: u64,
152    ) -> Result<Option<H256>, RollupStoreError> {
153        self.engine.get_commit_tx_by_batch(batch_number).await
154    }
155
156    pub async fn store_commit_tx_by_batch(
157        &self,
158        batch_number: u64,
159        commit_tx: H256,
160    ) -> Result<(), RollupStoreError> {
161        self.engine
162            .store_commit_tx_by_batch(batch_number, commit_tx)
163            .await
164    }
165
166    pub async fn get_verify_tx_by_batch(
167        &self,
168        batch_number: u64,
169    ) -> Result<Option<H256>, RollupStoreError> {
170        self.engine.get_verify_tx_by_batch(batch_number).await
171    }
172
173    pub async fn store_verify_tx_by_batch(
174        &self,
175        batch_number: u64,
176        verify_tx: H256,
177    ) -> Result<(), RollupStoreError> {
178        self.engine
179            .store_verify_tx_by_batch(batch_number, verify_tx)
180            .await
181    }
182
183    pub async fn get_batch_number(&self) -> Result<Option<u64>, RollupStoreError> {
184        self.engine.get_last_batch_number().await
185    }
186
187    pub async fn get_batch(
188        &self,
189        batch_number: u64,
190        fork: Fork,
191    ) -> Result<Option<Batch>, RollupStoreError> {
192        let Some(blocks) = self.get_block_numbers_by_batch(batch_number).await? else {
193            return Ok(None);
194        };
195
196        let first_block = *blocks.first().ok_or(RollupStoreError::Custom(
197            "Failed while trying to retrieve the first block of a known batch. This is a bug."
198                .to_owned(),
199        ))?;
200        let last_block = *blocks.last().ok_or(RollupStoreError::Custom(
201            "Failed while trying to retrieve the last block of a known batch. This is a bug."
202                .to_owned(),
203        ))?;
204
205        let state_root =
206            self.get_state_root_by_batch(batch_number)
207                .await?
208                .ok_or(RollupStoreError::Custom(
209                "Failed while trying to retrieve the state root of a known batch. This is a bug."
210                    .to_owned(),
211            ))?;
212
213        let blobs_bundle = BlobsBundle::create_from_blobs(
214            // Currently validium mode doesn't generate blobs, so no one will be stored
215            // TODO: If/When that behaviour change, this should throw error on None
216            &self
217                .get_blobs_by_batch(batch_number)
218                .await?
219                .unwrap_or_default(),
220                if fork <= Fork::Prague { None } else { Some(1) },
221        ).map_err(|e| {
222            RollupStoreError::Custom(format!("Failed to create blobs bundle from blob while getting batch from database: {e}. This is a bug"))
223        })?;
224
225        let l1_out_message_hashes = self
226            .get_l1_out_message_hashes_by_batch(batch_number)
227            .await?
228            .unwrap_or_default();
229
230        let balance_diffs = self
231            .get_balance_diffs_by_batch(batch_number)
232            .await?
233            .unwrap_or_default();
234
235        let l1_in_messages_rolling_hash = self
236            .get_l1_in_messages_rolling_hash_by_batch_number(batch_number)
237            .await?.ok_or(RollupStoreError::Custom(
238            "Failed while trying to retrieve the deposit logs hash of a known batch. This is a bug."
239                .to_owned(),
240        ))?;
241
242        let non_privileged_transactions = self
243            .engine
244            .get_non_privileged_transactions_by_batch(batch_number)
245            .await?
246            .ok_or(RollupStoreError::Custom(
247            "Failed while trying to retrieve the non-privileged transactions count of a known batch. This is a bug."
248                .to_owned(),
249        ))?;
250
251        let l2_in_message_rolling_hashes = self
252            .get_l2_in_message_rolling_hashes_by_batch(batch_number)
253            .await?
254            .ok_or(RollupStoreError::Custom(
255            "Failed while trying to retrieve the L2 in messages rolling hashes of a known batch. This is a bug."
256                .to_owned(),
257        ))?;
258
259        let commit_tx = self.get_commit_tx_by_batch(batch_number).await?;
260
261        let verify_tx = self.get_verify_tx_by_batch(batch_number).await?;
262
263        Ok(Some(Batch {
264            number: batch_number,
265            first_block,
266            last_block,
267            state_root,
268            blobs_bundle,
269            l1_out_message_hashes,
270            l1_in_messages_rolling_hash,
271            l2_in_message_rolling_hashes,
272            non_privileged_transactions,
273            balance_diffs,
274            commit_tx,
275            verify_tx,
276        }))
277    }
278
279    pub async fn seal_batch(&self, batch: Batch) -> Result<(), RollupStoreError> {
280        self.engine.seal_batch(batch).await
281    }
282
283    /// Seals a batch along with its prover input data in one atomic operation.
284    pub async fn seal_batch_with_prover_input(
285        &self,
286        batch: Batch,
287        prover_version: &str,
288        prover_input: ProverInputData,
289    ) -> Result<(), RollupStoreError> {
290        self.engine
291            .seal_batch_with_prover_input(batch, prover_version, prover_input)
292            .await
293    }
294
295    pub async fn update_operations_count(
296        &self,
297        transaction_inc: u64,
298        privileged_tx_inc: u64,
299        messages_inc: u64,
300    ) -> Result<(), RollupStoreError> {
301        self.engine
302            .update_operations_count(transaction_inc, privileged_tx_inc, messages_inc)
303            .await
304    }
305
306    pub async fn get_operations_count(&self) -> Result<[u64; 3], RollupStoreError> {
307        self.engine.get_operations_count().await
308    }
309
310    /// Returns whether the batch with the given number is present.
311    pub async fn contains_batch(&self, batch_number: &u64) -> Result<bool, RollupStoreError> {
312        self.engine.contains_batch(batch_number).await
313    }
314
315    /// Stores the sequencer signature for a given block hash.
316    /// When the lead sequencer sends a block by P2P, it signs the message and it is validated
317    /// If we want to gossip or broadcast the message, we need to store the signature for later use
318    pub async fn store_signature_by_block(
319        &self,
320        block_hash: H256,
321        signature: ethereum_types::Signature,
322    ) -> Result<(), RollupStoreError> {
323        self.engine
324            .store_signature_by_block(block_hash, signature)
325            .await
326    }
327
328    /// Returns the sequencer signature for a given block hash.
329    /// We want to retrieve the validated signature to broadcast or gossip the block to the peers
330    /// So they can also validate the message
331    pub async fn get_signature_by_block(
332        &self,
333        block_hash: H256,
334    ) -> Result<Option<ethereum_types::Signature>, RollupStoreError> {
335        self.engine.get_signature_by_block(block_hash).await
336    }
337
338    /// Stores the sequencer signature for a given batch number.
339    /// When the lead sequencer sends a batch by P2P, it
340    /// should also sign it, this will map a batch number
341    /// to the batch's signature.
342    pub async fn store_signature_by_batch(
343        &self,
344        batch_number: u64,
345        signature: ethereum_types::Signature,
346    ) -> Result<(), RollupStoreError> {
347        self.engine
348            .store_signature_by_batch(batch_number, signature)
349            .await
350    }
351
352    /// Returns the sequencer signature for a given batch number.
353    /// This is used mostly in P2P to avoid signing an
354    /// already known batch.
355    pub async fn get_signature_by_batch(
356        &self,
357        batch_number: u64,
358    ) -> Result<Option<ethereum_types::Signature>, RollupStoreError> {
359        self.engine.get_signature_by_batch(batch_number).await
360    }
361
362    /// Returns `(batch_number, verified_at_secs)` for the latest batch verified on-chain.
363    pub async fn get_latest_verified_batch_proof(&self) -> Result<(u64, u64), RollupStoreError> {
364        self.engine.get_latest_verified_batch_proof().await
365    }
366
367    /// Records that `batch_number` was verified on-chain at `verified_at` (unix secs).
368    pub async fn set_latest_verified_batch_proof(
369        &self,
370        batch_number: u64,
371        verified_at: u64,
372    ) -> Result<(), RollupStoreError> {
373        self.engine
374            .set_latest_verified_batch_proof(batch_number, verified_at)
375            .await
376    }
377
378    /// Returns the batch number for the latest proof sent to the Aligned gateway.
379    pub async fn get_latest_sent_to_aligned(&self) -> Result<u64, RollupStoreError> {
380        self.engine.get_latest_sent_to_aligned().await
381    }
382
383    /// Records that `batch_number` was sent to the Aligned gateway.
384    pub async fn set_latest_sent_to_aligned(
385        &self,
386        batch_number: u64,
387    ) -> Result<(), RollupStoreError> {
388        self.engine.set_latest_sent_to_aligned(batch_number).await
389    }
390
391    /// Returns the account updates yielded from executing a block
392    pub async fn get_account_updates_by_block_number(
393        &self,
394        block_number: BlockNumber,
395    ) -> Result<Option<Vec<AccountUpdate>>, RollupStoreError> {
396        self.engine
397            .get_account_updates_by_block_number(block_number)
398            .await
399    }
400
401    /// Stores the account updates yielded from executing a block
402    pub async fn store_account_updates_by_block_number(
403        &self,
404        block_number: BlockNumber,
405        account_updates: Vec<AccountUpdate>,
406    ) -> Result<(), RollupStoreError> {
407        self.engine
408            .store_account_updates_by_block_number(block_number, account_updates)
409            .await
410    }
411
412    pub async fn store_proof_by_batch_and_type(
413        &self,
414        batch_number: u64,
415        proof_type: ProverType,
416        proof: ProverOutput,
417    ) -> Result<(), RollupStoreError> {
418        self.engine
419            .store_proof_by_batch_and_type(batch_number, proof_type, proof)
420            .await
421    }
422
423    pub async fn get_proof_by_batch_and_type(
424        &self,
425        batch_number: u64,
426        proof_type: ProverType,
427    ) -> Result<Option<ProverOutput>, RollupStoreError> {
428        self.engine
429            .get_proof_by_batch_and_type(batch_number, proof_type)
430            .await
431    }
432
433    /// Reverts to a previous batch, discarding operations in them
434    pub async fn revert_to_batch(&self, batch_number: u64) -> Result<(), RollupStoreError> {
435        self.engine.revert_to_batch(batch_number).await
436    }
437
438    pub async fn delete_proof_by_batch_and_type(
439        &self,
440        batch_number: u64,
441        proof_type: ProverType,
442    ) -> Result<(), RollupStoreError> {
443        self.engine
444            .delete_proof_by_batch_and_type(batch_number, proof_type)
445            .await
446    }
447
448    pub async fn store_prover_input_by_batch_and_version(
449        &self,
450        batch_number: u64,
451        prover_version: &str,
452        prover_input: ProverInputData,
453    ) -> Result<(), RollupStoreError> {
454        self.engine
455            .store_prover_input_by_batch_and_version(batch_number, prover_version, prover_input)
456            .await
457    }
458
459    pub async fn get_prover_input_by_batch_and_version(
460        &self,
461        batch_number: u64,
462        prover_version: &str,
463    ) -> Result<Option<ProverInputData>, RollupStoreError> {
464        self.engine
465            .get_prover_input_by_batch_and_version(batch_number, prover_version)
466            .await
467    }
468
469    pub async fn store_fee_config_by_block(
470        &self,
471        block_number: BlockNumber,
472        fee_config: FeeConfig,
473    ) -> Result<(), RollupStoreError> {
474        self.engine
475            .store_fee_config_by_block(block_number, fee_config)
476            .await
477    }
478    pub async fn get_fee_config_by_block(
479        &self,
480        block_number: BlockNumber,
481    ) -> Result<Option<FeeConfig>, RollupStoreError> {
482        self.engine.get_fee_config_by_block(block_number).await
483    }
484}