anvil_zksync_l1_sidecar/
l1_executor.rs

1use crate::commitment_generator::CommitmentGenerator;
2use crate::l1_sender::L1SenderHandle;
3use std::time::Duration;
4use tokio::sync::watch;
5use zksync_types::L1BatchNumber;
6
7#[derive(Debug, Clone)]
8pub struct L1Executor {
9    mode: L1ExecutorMode,
10}
11
12impl L1Executor {
13    /// Batches will not be executed on L1 unless requested manually through JSON RPC API.
14    pub fn manual() -> Self {
15        Self {
16            mode: L1ExecutorMode::Manual,
17        }
18    }
19
20    /// Batches will be executed on L1 shortly after they get sealed.
21    pub fn auto(
22        commitment_generator: CommitmentGenerator,
23        l1_sender_handle: L1SenderHandle,
24    ) -> Self {
25        Self {
26            mode: L1ExecutorMode::Auto(L1ExecutorModeAuto {
27                last_executed_batch: L1BatchNumber(0),
28                commitment_generator,
29                l1_sender_handle,
30            }),
31        }
32    }
33
34    pub async fn run(self, stop_receiver: &mut watch::Receiver<bool>) -> anyhow::Result<()> {
35        match self.mode {
36            L1ExecutorMode::Manual => {
37                stop_receiver.changed().await?;
38                Ok(())
39            }
40            L1ExecutorMode::Auto(executor) => executor.run(stop_receiver).await,
41        }
42    }
43}
44
45#[derive(Debug, Clone)]
46enum L1ExecutorMode {
47    Manual,
48    Auto(L1ExecutorModeAuto),
49}
50
51#[derive(Debug, Clone)]
52struct L1ExecutorModeAuto {
53    last_executed_batch: L1BatchNumber,
54    commitment_generator: CommitmentGenerator,
55    l1_sender_handle: L1SenderHandle,
56}
57
58impl L1ExecutorModeAuto {
59    async fn run(mut self, stop_receiver: &mut watch::Receiver<bool>) -> anyhow::Result<()> {
60        const POLL_INTERVAL: Duration = Duration::from_millis(100);
61
62        loop {
63            if *stop_receiver.borrow() {
64                tracing::info!("automatic L1 executor was interrupted");
65                return Ok(());
66            }
67            let next_batch = self.last_executed_batch + 1;
68            let Some(batch_with_metadata) = self
69                .commitment_generator
70                .get_or_generate_metadata(next_batch)
71                .await
72            else {
73                tracing::trace!(batch_number=%next_batch, "batch is not ready to be executed yet");
74                tokio::time::timeout(POLL_INTERVAL, stop_receiver.changed())
75                    .await
76                    .ok();
77                continue;
78            };
79            self.l1_sender_handle
80                .commit_sync(batch_with_metadata.clone())
81                .await?;
82            self.l1_sender_handle
83                .prove_sync(batch_with_metadata.clone())
84                .await?;
85            self.l1_sender_handle
86                .execute_sync(batch_with_metadata)
87                .await?;
88            tracing::debug!(batch_number=%next_batch, "batch has been automatically executed on L1");
89            self.last_executed_batch = next_batch;
90        }
91    }
92}