diff --git a/Cargo.lock b/Cargo.lock index ad29cbeceee..718e315b541 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3758,8 +3758,10 @@ dependencies = [ "ethrex-trie 4.0.0", "ethrex-vm", "lambdaworks-crypto 0.11.0", + "rkyv", "secp256k1", "serde", + "serde_with", "sha3", "thiserror 2.0.17", ] @@ -4083,6 +4085,7 @@ dependencies = [ "ethrex-trie 4.0.0", "futures", "libsql", + "rkyv", "thiserror 2.0.17", "tokio", "tracing", diff --git a/crates/l2/common/Cargo.toml b/crates/l2/common/Cargo.toml index c8d0a4ada79..b84418c3e2b 100644 --- a/crates/l2/common/Cargo.toml +++ b/crates/l2/common/Cargo.toml @@ -12,12 +12,18 @@ ethrex-rlp.workspace = true ethrex-storage.workspace = true ethrex-trie.workspace = true ethrex-vm.workspace = true + bytes.workspace = true thiserror.workspace = true serde.workspace = true lambdaworks-crypto.workspace = true sha3.workspace = true secp256k1.workspace = true +serde_with.workspace = true +# We do not need to enable the "unaligned" feature here since we are just using +# rkyv for ProverInputData, a data structure meant to be used in the host and not +# inside a guest program +rkyv.workspace = true [lints.clippy] unwrap_used = "deny" diff --git a/crates/l2/common/src/prover.rs b/crates/l2/common/src/prover.rs index 3c92e7c3e88..b870d2fb779 100644 --- a/crates/l2/common/src/prover.rs +++ b/crates/l2/common/src/prover.rs @@ -1,8 +1,26 @@ +use ethrex_common::types::{ + Block, blobs_bundle, block_execution_witness::ExecutionWitness, fee_config::FeeConfig, +}; +use rkyv::{Archive, Deserialize as RDeserialize, Serialize as RSerialize}; use serde::{Deserialize, Serialize}; +use serde_with::serde_as; use std::fmt::{Debug, Display}; use crate::calldata::Value; +#[serde_as] +#[derive(Serialize, Deserialize, RDeserialize, RSerialize, Archive)] +pub struct ProverInputData { + pub blocks: Vec, + pub execution_witness: ExecutionWitness, + pub elasticity_multiplier: u64, + #[serde_as(as = "[_; 48]")] + pub blob_commitment: blobs_bundle::Commitment, + #[serde_as(as = "[_; 48]")] + pub blob_proof: blobs_bundle::Proof, + pub fee_config: FeeConfig, +} + /// Enum used to identify the different proving systems. #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)] pub enum ProverType { diff --git a/crates/l2/prover/src/guest_program/src/risc0/Cargo.lock b/crates/l2/prover/src/guest_program/src/risc0/Cargo.lock index 7692e0a8240..097d97559a1 100644 --- a/crates/l2/prover/src/guest_program/src/risc0/Cargo.lock +++ b/crates/l2/prover/src/guest_program/src/risc0/Cargo.lock @@ -1248,8 +1248,10 @@ dependencies = [ "ethrex-trie", "ethrex-vm", "lambdaworks-crypto", + "rkyv", "secp256k1", "serde", + "serde_with", "sha3", "thiserror", ] diff --git a/crates/l2/prover/src/guest_program/src/sp1/Cargo.lock b/crates/l2/prover/src/guest_program/src/sp1/Cargo.lock index 0c3900fd8fa..c3e6d8b7350 100644 --- a/crates/l2/prover/src/guest_program/src/sp1/Cargo.lock +++ b/crates/l2/prover/src/guest_program/src/sp1/Cargo.lock @@ -1026,8 +1026,10 @@ dependencies = [ "ethrex-trie", "ethrex-vm", "lambdaworks-crypto", + "rkyv", "secp256k1", "serde", + "serde_with", "sha3", "thiserror", ] diff --git a/crates/l2/prover/src/prover.rs b/crates/l2/prover/src/prover.rs index 8894f3dcc98..fed95cabf9d 100644 --- a/crates/l2/prover/src/prover.rs +++ b/crates/l2/prover/src/prover.rs @@ -1,5 +1,5 @@ use crate::{backend::Backend, config::ProverConfig, prove, to_batch_proof}; -use ethrex_l2::sequencer::proof_coordinator::{ProofData, get_commit_hash}; +use ethrex_l2::sequencer::{proof_coordinator::ProofData, utils::get_git_commit_hash}; use ethrex_l2_common::prover::BatchProof; use guest_program::input::ProgramInput; use std::time::Duration; @@ -38,7 +38,7 @@ impl Prover { proof_coordinator_endpoints: cfg.proof_coordinators, proving_time_ms: cfg.proving_time_ms, aligned_mode: cfg.aligned_mode, - commit_hash: get_commit_hash(), + commit_hash: get_git_commit_hash(), #[cfg(all(feature = "sp1", feature = "gpu"))] sp1_server: cfg.sp1_server, } diff --git a/crates/l2/sequencer/errors.rs b/crates/l2/sequencer/errors.rs index 67afeafd84d..324672278e3 100644 --- a/crates/l2/sequencer/errors.rs +++ b/crates/l2/sequencer/errors.rs @@ -121,6 +121,8 @@ pub enum ProofCoordinatorError { MissingTDXPrivateKey, #[error("Metrics error")] Metrics(#[from] MetricsError), + #[error("Missing prover input for batch {0} (version {1})")] + MissingBatchProverInput(u64, String), } #[derive(Debug, thiserror::Error)] @@ -261,6 +263,8 @@ pub enum CommitterError { UnexpectedError(String), #[error("Unreachable code reached: {0}")] Unreachable(String), + #[error("Failed to generate batch witness: {0}")] + FailedToGenerateBatchWitness(#[source] ChainError), } #[derive(Debug, thiserror::Error)] diff --git a/crates/l2/sequencer/l1_committer.rs b/crates/l2/sequencer/l1_committer.rs index 39acc11b10b..6da12dfe2ca 100644 --- a/crates/l2/sequencer/l1_committer.rs +++ b/crates/l2/sequencer/l1_committer.rs @@ -1,14 +1,14 @@ use crate::{ - CommitterConfig, EthConfig, SequencerConfig, + BlockProducerConfig, CommitterConfig, EthConfig, SequencerConfig, based::sequencer_state::{SequencerState, SequencerStatus}, sequencer::{ errors::CommitterError, - utils::{self, system_now_ms}, + utils::{self, fetch_batch_blocks, get_git_commit_hash, system_now_ms}, }, }; use bytes::Bytes; -use ethrex_blockchain::{Blockchain, vm::StoreVmDatabase}; +use ethrex_blockchain::{Blockchain, BlockchainType, vm::StoreVmDatabase}; use ethrex_common::{ Address, H256, U256, types::{ @@ -24,6 +24,7 @@ use ethrex_l2_common::{ PRIVILEGED_TX_BUDGET, compute_privileged_transactions_hash, get_block_privileged_transactions, }, + prover::ProverInputData, state_diff::{StateDiff, prepare_state_diff}, }; use ethrex_l2_rpc::signer::{Signer, SignerHealth}; @@ -103,6 +104,10 @@ pub struct L1Committer { last_committed_batch: u64, /// Cancellation token for the next inbound InMessage::Commit cancellation_token: Option, + /// Elasticity multiplier for prover input generation + elasticity_multiplier: u64, + /// Git commit hash of the build + git_commit_hash: String, } #[derive(Clone, Serialize)] @@ -125,6 +130,7 @@ impl L1Committer { #[allow(clippy::too_many_arguments)] pub async fn new( committer_config: &CommitterConfig, + proposer_config: &BlockProducerConfig, eth_config: &EthConfig, blockchain: Arc, store: Store, @@ -163,6 +169,8 @@ impl L1Committer { last_committed_batch_timestamp: 0, last_committed_batch, cancellation_token: None, + elasticity_multiplier: proposer_config.elasticity_multiplier, + git_commit_hash: get_git_commit_hash(), }) } @@ -175,6 +183,7 @@ impl L1Committer { ) -> Result, CommitterError> { let state = Self::new( &cfg.l1_committer, + &cfg.block_producer, &cfg.eth, blockchain, store.clone(), @@ -264,6 +273,15 @@ impl L1Committer { } }; + info!( + first_block = batch.first_block, + last_block = batch.last_block, + "Generating and storing witness for batch {}", + batch.number, + ); + + self.generate_and_store_batch_prover_input(&batch).await?; + info!( first_block = batch.first_block, last_block = batch.last_block, @@ -536,6 +554,71 @@ impl L1Committer { )) } + async fn generate_and_store_batch_prover_input( + &self, + batch: &Batch, + ) -> Result<(), CommitterError> { + let blocks = + fetch_batch_blocks::(batch.number, &self.store, &self.rollup_store) + .await?; + + let batch_witness = self + .blockchain + .generate_witness_for_blocks(&blocks) + .await + .map_err(CommitterError::FailedToGenerateBatchWitness)?; + + // We still need to differentiate the validium case because for validium + // we are generating the BlobsBundle with BlobsBundle::default which + // sets the commitments and proofs to empty vectors. + let (blob_commitment, blob_proof) = if self.validium { + ([0; 48], [0; 48]) + } else { + let BlobsBundle { + commitments, + proofs, + .. + } = &batch.blobs_bundle; + + ( + commitments + .first() + .cloned() + .ok_or(CommitterError::Unreachable( + "Blob commitment missing in batch blobs bundle".to_string(), + ))?, + proofs.first().cloned().ok_or(CommitterError::Unreachable( + "Blob proof missing in batch blobs bundle".to_string(), + ))?, + ) + }; + + let BlockchainType::L2(fee_config) = self.blockchain.options.r#type else { + return Err(CommitterError::Unreachable( + "Batch witness generation is only supported for L2 blockchains".to_string(), + )); + }; + + let prover_input = ProverInputData { + blocks, + execution_witness: batch_witness, + elasticity_multiplier: self.elasticity_multiplier, + blob_commitment, + blob_proof, + fee_config, + }; + + self.rollup_store + .store_prover_input_by_batch_and_version( + batch.number, + &self.git_commit_hash, + prover_input, + ) + .await?; + + Ok(()) + } + async fn send_commitment(&mut self, batch: &Batch) -> Result { let messages_merkle_root = compute_merkle_root(&batch.message_hashes); let last_block_hash = get_last_block_hash(&self.store, batch.last_block)?; @@ -551,22 +634,11 @@ impl L1Committer { let (commit_function_signature, values) = if self.based { let mut encoded_blocks: Vec = Vec::new(); - for i in batch.first_block..=batch.last_block { - let block_header = self - .store - .get_block_header(i) - .map_err(CommitterError::from)? - .ok_or(CommitterError::FailedToRetrieveDataFromStorage)?; - - let block_body = self - .store - .get_block_body(i) - .await - .map_err(CommitterError::from)? - .ok_or(CommitterError::FailedToRetrieveDataFromStorage)?; - - let block = Block::new(block_header, block_body); + let blocks = + fetch_batch_blocks::(batch.number, &self.store, &self.rollup_store) + .await?; + for block in blocks { encoded_blocks.push(block.encode_to_vec().into()); } @@ -747,7 +819,7 @@ impl GenServer for L1Committer { let commit_time: u128 = self.commit_time_ms.into(); let should_send_commitment = current_time - self.last_committed_batch_timestamp > commit_time; - #[allow(clippy::collapsible_if)] + #[expect(clippy::collapsible_if)] if should_send_commitment { if self .commit_next_batch_to_l1() diff --git a/crates/l2/sequencer/mod.rs b/crates/l2/sequencer/mod.rs index 0981de56963..9cf172aa779 100644 --- a/crates/l2/sequencer/mod.rs +++ b/crates/l2/sequencer/mod.rs @@ -110,10 +110,8 @@ pub async fn start_l2( error!("Error starting Committer: {err}"); }); let _ = ProofCoordinator::spawn( - store.clone(), rollup_store.clone(), cfg.clone(), - blockchain.clone(), needed_proof_types.clone(), ) .await diff --git a/crates/l2/sequencer/proof_coordinator.rs b/crates/l2/sequencer/proof_coordinator.rs index c360e6eb3e6..572bb176475 100644 --- a/crates/l2/sequencer/proof_coordinator.rs +++ b/crates/l2/sequencer/proof_coordinator.rs @@ -1,26 +1,15 @@ use crate::sequencer::errors::{ConnectionHandlerError, ProofCoordinatorError}; use crate::sequencer::setup::{prepare_quote_prerequisites, register_tdx_key}; -use crate::sequencer::utils::get_latest_sent_batch; -use crate::{ - BlockProducerConfig, CommitterConfig, EthConfig, ProofCoordinatorConfig, SequencerConfig, -}; +use crate::sequencer::utils::{get_git_commit_hash, get_latest_sent_batch}; +use crate::{CommitterConfig, EthConfig, ProofCoordinatorConfig, SequencerConfig}; use bytes::Bytes; -use ethrex_blockchain::{Blockchain, BlockchainType}; -use ethrex_common::types::BlobsBundle; -use ethrex_common::types::block_execution_witness::ExecutionWitness; -use ethrex_common::types::fee_config::FeeConfig; -use ethrex_common::{ - Address, - types::{Block, blobs_bundle}, -}; -use ethrex_l2_common::prover::{BatchProof, ProverType}; +use ethrex_common::Address; +use ethrex_l2_common::prover::{BatchProof, ProverInputData, ProverType}; use ethrex_metrics::metrics; use ethrex_rpc::clients::eth::EthClient; -use ethrex_storage::Store; use ethrex_storage_rollup::StoreRollup; use secp256k1::SecretKey; use serde::{Deserialize, Serialize}; -use serde_with::serde_as; use spawned_concurrency::messages::Unused; use spawned_concurrency::tasks::{CastResponse, GenServer, GenServerHandle}; use std::net::{IpAddr, SocketAddr}; @@ -38,21 +27,6 @@ use std::{collections::HashMap, time::SystemTime}; #[cfg(feature = "metrics")] use tokio::sync::Mutex; -#[serde_as] -#[derive(Serialize, Deserialize)] -pub struct ProverInputData { - pub blocks: Vec, - pub execution_witness: ExecutionWitness, - pub elasticity_multiplier: u64, - #[cfg(feature = "l2")] - #[serde_as(as = "[_; 48]")] - pub blob_commitment: blobs_bundle::Commitment, - #[cfg(feature = "l2")] - #[serde_as(as = "[_; 48]")] - pub blob_proof: blobs_bundle::Proof, - pub fee_config: FeeConfig, -} - /// Enum for the ProverServer <--> ProverClient Communication Protocol. #[allow(clippy::large_enum_variant)] #[derive(Serialize, Deserialize)] @@ -154,10 +128,6 @@ impl ProofData { } } -pub fn get_commit_hash() -> String { - env!("VERGEN_GIT_SHA").to_string() -} - #[derive(Clone)] pub enum ProofCordInMessage { Listen { listener: Arc }, @@ -172,32 +142,24 @@ pub enum ProofCordOutMessage { pub struct ProofCoordinator { listen_ip: IpAddr, port: u16, - store: Store, eth_client: EthClient, on_chain_proposer_address: Address, - elasticity_multiplier: u64, rollup_store: StoreRollup, rpc_url: String, tdx_private_key: Option, - blockchain: Arc, - validium: bool, needed_proof_types: Vec, - commit_hash: String, + git_commit_hash: String, #[cfg(feature = "metrics")] request_timestamp: Arc>>, qpl_tool_path: Option, } impl ProofCoordinator { - #[allow(clippy::too_many_arguments)] pub async fn new( config: &ProofCoordinatorConfig, committer_config: &CommitterConfig, eth_config: &EthConfig, - proposer_config: &BlockProducerConfig, - store: Store, rollup_store: StoreRollup, - blockchain: Arc, needed_proof_types: Vec, ) -> Result { let eth_client = EthClient::new_with_config( @@ -222,17 +184,13 @@ impl ProofCoordinator { Ok(Self { listen_ip: config.listen_ip, port: config.listen_port, - store, eth_client, on_chain_proposer_address, - elasticity_multiplier: proposer_config.elasticity_multiplier, rollup_store, rpc_url, tdx_private_key: config.tdx_private_key, - blockchain, - validium: config.validium, needed_proof_types, - commit_hash: get_commit_hash(), + git_commit_hash: get_git_commit_hash(), #[cfg(feature = "metrics")] request_timestamp: Arc::new(Mutex::new(HashMap::new())), qpl_tool_path: config.qpl_tool_path.clone(), @@ -240,20 +198,15 @@ impl ProofCoordinator { } pub async fn spawn( - store: Store, rollup_store: StoreRollup, cfg: SequencerConfig, - blockchain: Arc, needed_proof_types: Vec, ) -> Result<(), ProofCoordinatorError> { let state = Self::new( &cfg.proof_coordinator, &cfg.l1_committer, &cfg.eth, - &cfg.block_producer, - store, rollup_store, - blockchain, needed_proof_types, ) .await?; @@ -299,13 +252,13 @@ impl ProofCoordinator { ) -> Result<(), ProofCoordinatorError> { info!("BatchRequest received"); - if commit_hash != self.commit_hash { + if commit_hash != self.git_commit_hash { error!( "Code version mismatch: expected {}, got {}", - self.commit_hash, commit_hash + self.git_commit_hash, commit_hash ); - let response = ProofData::invalid_code_version(self.commit_hash.clone()); + let response = ProofData::invalid_code_version(self.git_commit_hash.clone()); send_response(stream, &response).await?; info!("InvalidCodeVersion sent"); return Ok(()); @@ -338,7 +291,16 @@ impl ProofCoordinator { debug!("Sending empty BatchResponse"); ProofData::empty_batch_response() } else { - let input = self.create_prover_input(batch_to_verify).await?; + let Some(input) = self + .rollup_store + .get_prover_input_by_batch_and_version(batch_to_verify, &self.git_commit_hash) + .await? + else { + return Err(ProofCoordinatorError::MissingBatchProverInput( + batch_to_verify, + self.git_commit_hash.clone(), + )); + }; debug!("Sending BatchResponse for block_number: {batch_to_verify}"); metrics!( // First request starts a timer until a proof is received. The elapsed time will be @@ -457,89 +419,6 @@ impl ProofCoordinator { info!("ProverSetupACK sent"); Ok(()) } - - async fn create_prover_input( - &mut self, - batch_number: u64, - ) -> Result { - // Get blocks in batch - let Some(block_numbers) = self - .rollup_store - .get_block_numbers_by_batch(batch_number) - .await? - else { - return Err(ProofCoordinatorError::ItemNotFoundInStore(format!( - "Batch number {batch_number} not found in store" - ))); - }; - - let blocks = self.fetch_blocks(block_numbers).await?; - - let witness = self - .blockchain - .generate_witness_for_blocks(&blocks) - .await - .map_err(ProofCoordinatorError::from)?; - - // Get blobs bundle cached by the L1 Committer (blob, commitment, proof) - let (blob_commitment, blob_proof) = if self.validium { - ([0; 48], [0; 48]) - } else { - let blob = self - .rollup_store - .get_blobs_by_batch(batch_number) - .await? - .ok_or(ProofCoordinatorError::MissingBlob(batch_number))?; - let BlobsBundle { - mut commitments, - mut proofs, - .. - } = BlobsBundle::create_from_blobs(&blob)?; - match (commitments.pop(), proofs.pop()) { - (Some(commitment), Some(proof)) => (commitment, proof), - _ => return Err(ProofCoordinatorError::MissingBlob(batch_number)), - } - }; - - debug!("Created prover input for batch {batch_number}"); - - let BlockchainType::L2(fee_config) = self.blockchain.options.r#type else { - return Err(ProofCoordinatorError::InternalError( - "Invalid blockchain type, expected L2".to_string(), - )); - }; - - Ok(ProverInputData { - execution_witness: witness, - blocks, - elasticity_multiplier: self.elasticity_multiplier, - #[cfg(feature = "l2")] - blob_commitment, - #[cfg(feature = "l2")] - blob_proof, - fee_config, - }) - } - - async fn fetch_blocks( - &mut self, - block_numbers: Vec, - ) -> Result, ProofCoordinatorError> { - let mut blocks = vec![]; - for block_number in block_numbers { - let header = self - .store - .get_block_header(block_number)? - .ok_or(ProofCoordinatorError::StorageDataIsNone)?; - let body = self - .store - .get_block_body(block_number) - .await? - .ok_or(ProofCoordinatorError::StorageDataIsNone)?; - blocks.push(Block::new(header, body)); - } - Ok(blocks) - } } impl GenServer for ProofCoordinator { diff --git a/crates/l2/sequencer/utils.rs b/crates/l2/sequencer/utils.rs index aacb4030082..975664efdd9 100644 --- a/crates/l2/sequencer/utils.rs +++ b/crates/l2/sequencer/utils.rs @@ -1,4 +1,5 @@ use aligned_sdk::common::types::Network; +use ethrex_common::types::Block; use ethrex_common::utils::keccak; use ethrex_common::{Address, H160, H256, types::TxType}; use ethrex_l2_common::prover::ProverType; @@ -11,6 +12,8 @@ use ethrex_rpc::{ EthClient, clients::{EthClientError, Overrides}, }; +use ethrex_storage::Store; +use ethrex_storage::error::StoreError; use ethrex_storage_rollup::{RollupStoreError, StoreRollup}; use rand::Rng; use std::time::{Duration, SystemTime}; @@ -159,3 +162,47 @@ where Ok(is_up_to_date) } + +pub async fn fetch_batch_blocks( + batch_number: u64, + store: &Store, + rollup_store: &StoreRollup, +) -> Result, E> +where + E: From + From, +{ + let batch_blocks = rollup_store + .get_block_numbers_by_batch(batch_number) + .await? + .ok_or(RollupStoreError::Custom( + "failed to retrieve data from storage".to_string(), + ))?; + + let mut blocks = Vec::new(); + + for block_number in batch_blocks { + let block_header = store + .get_block_header(block_number)? + .ok_or(StoreError::Custom( + "failed to retrieve data from storage".to_string(), + ))?; + + let block_body = store + .get_block_body(block_number) + .await? + .ok_or(StoreError::Custom( + "failed to retrieve data from storage".to_string(), + ))?; + + let block = Block::new(block_header, block_body); + + blocks.push(block); + } + + Ok(blocks) +} + +/// Returns the git commit hash of the current build. +pub fn get_git_commit_hash() -> String { + env!("VERGEN_GIT_SHA").to_string() +} diff --git a/crates/l2/storage/Cargo.toml b/crates/l2/storage/Cargo.toml index e5bfaf5dac5..c588f7fa237 100644 --- a/crates/l2/storage/Cargo.toml +++ b/crates/l2/storage/Cargo.toml @@ -24,6 +24,10 @@ libsql = { workspace = true, optional = true } # We only need the runtime for the blocking databases to spawn blocking tasks tokio = { workspace = true, optional = true, features = ["rt", "test-util"] } bincode = "1.3.3" +# We do not need to enable the "unaligned" feature here since we are just using +# rkyv to store the ExecutionWitness in the database to be used by the +# ProofCoordinator process +rkyv.workspace = true [features] default = [] diff --git a/crates/l2/storage/src/api.rs b/crates/l2/storage/src/api.rs index d16c0ff88ad..afc96b44ad6 100644 --- a/crates/l2/storage/src/api.rs +++ b/crates/l2/storage/src/api.rs @@ -6,7 +6,7 @@ use ethrex_common::{ H256, types::{AccountUpdate, Blob, BlockNumber, batch::Batch}, }; -use ethrex_l2_common::prover::{BatchProof, ProverType}; +use ethrex_l2_common::prover::{BatchProof, ProverInputData, ProverType}; use crate::error::RollupStoreError; @@ -147,4 +147,17 @@ pub trait StoreEngineRollup: Debug + Send + Sync { ) -> Result<(), RollupStoreError>; async fn revert_to_batch(&self, batch_number: u64) -> Result<(), RollupStoreError>; + + async fn store_prover_input_by_batch_and_version( + &self, + batch_number: u64, + prover_version: &str, + prover_input: ProverInputData, + ) -> Result<(), RollupStoreError>; + + async fn get_prover_input_by_batch_and_version( + &self, + batch_number: u64, + prover_version: &str, + ) -> Result, RollupStoreError>; } diff --git a/crates/l2/storage/src/store.rs b/crates/l2/storage/src/store.rs index 62df78a2a9a..2770cc51cb4 100644 --- a/crates/l2/storage/src/store.rs +++ b/crates/l2/storage/src/store.rs @@ -9,7 +9,7 @@ use ethrex_common::{ H256, types::{AccountUpdate, Blob, BlobsBundle, BlockNumber, batch::Batch}, }; -use ethrex_l2_common::prover::{BatchProof, ProverType}; +use ethrex_l2_common::prover::{BatchProof, ProverInputData, ProverType}; use tracing::info; #[derive(Debug, Clone)] @@ -355,4 +355,25 @@ impl Store { .delete_proof_by_batch_and_type(batch_number, proof_type) .await } + + pub async fn store_prover_input_by_batch_and_version( + &self, + batch_number: u64, + prover_version: &str, + prover_input: ProverInputData, + ) -> Result<(), RollupStoreError> { + self.engine + .store_prover_input_by_batch_and_version(batch_number, prover_version, prover_input) + .await + } + + pub async fn get_prover_input_by_batch_and_version( + &self, + batch_number: u64, + prover_version: &str, + ) -> Result, RollupStoreError> { + self.engine + .get_prover_input_by_batch_and_version(batch_number, prover_version) + .await + } } diff --git a/crates/l2/storage/src/store_db/in_memory.rs b/crates/l2/storage/src/store_db/in_memory.rs index b5cfeeeb9a9..1a30ddd069f 100644 --- a/crates/l2/storage/src/store_db/in_memory.rs +++ b/crates/l2/storage/src/store_db/in_memory.rs @@ -9,7 +9,7 @@ use ethrex_common::{ H256, types::{AccountUpdate, Blob, BlockNumber, batch::Batch}, }; -use ethrex_l2_common::prover::{BatchProof, ProverType}; +use ethrex_l2_common::prover::{BatchProof, ProverInputData, ProverType}; use crate::api::StoreEngineRollup; @@ -46,6 +46,8 @@ struct StoreInner { commit_txs: HashMap, /// Map of batch number to verify transaction hash verify_txs: HashMap, + /// Map of (batch_number, prover_version) to serialized prover input data + batch_prover_input: HashMap<(u64, String), Vec>, } impl Store { @@ -287,6 +289,9 @@ impl StoreEngineRollup for Store { .retain(|batch, _| *batch <= batch_number); store.state_roots.retain(|batch, _| *batch <= batch_number); store.blobs.retain(|batch, _| *batch <= batch_number); + store + .batch_prover_input + .retain(|(batch, _), _| *batch <= batch_number); Ok(()) } @@ -334,6 +339,47 @@ impl StoreEngineRollup for Store { async fn get_last_batch_number(&self) -> Result, RollupStoreError> { Ok(self.inner()?.state_roots.keys().max().cloned()) } + + async fn store_prover_input_by_batch_and_version( + &self, + batch_number: u64, + prover_version: &str, + prover_input: ProverInputData, + ) -> Result<(), RollupStoreError> { + let witness_bytes = rkyv::to_bytes::(&prover_input) + .map_err(|e| RollupStoreError::Custom(format!("Failed to serialize witness: {}", e)))? + .to_vec(); + + self.inner()? + .batch_prover_input + .insert((batch_number, prover_version.to_string()), witness_bytes); + + Ok(()) + } + + async fn get_prover_input_by_batch_and_version( + &self, + batch_number: u64, + prover_version: &str, + ) -> Result, RollupStoreError> { + let Some(witness_bytes) = self + .inner()? + .batch_prover_input + .get(&(batch_number, prover_version.to_string())) + .cloned() + else { + return Ok(None); + }; + + let prover_input = rkyv::from_bytes::(&witness_bytes) + .map_err(|e| { + RollupStoreError::Custom(format!( + "Failed to deserialize prover input for batch {batch_number} and version {prover_version}: {e}", + )) + })?; + + Ok(Some(prover_input)) + } } impl Debug for Store { diff --git a/crates/l2/storage/src/store_db/sql.rs b/crates/l2/storage/src/store_db/sql.rs index 8c38a0b57b6..b6917b1515c 100644 --- a/crates/l2/storage/src/store_db/sql.rs +++ b/crates/l2/storage/src/store_db/sql.rs @@ -6,7 +6,7 @@ use ethrex_common::{ H256, types::{AccountUpdate, Blob, BlockNumber, batch::Batch}, }; -use ethrex_l2_common::prover::{BatchProof, ProverType}; +use ethrex_l2_common::prover::{BatchProof, ProverInputData, ProverType}; use libsql::{ Builder, Connection, Row, Rows, Transaction, Value, @@ -28,7 +28,7 @@ impl Debug for SQLStore { } } -const DB_SCHEMA: [&str; 15] = [ +const DB_SCHEMA: [&str; 16] = [ "CREATE TABLE blocks (block_number INT PRIMARY KEY, batch INT)", "CREATE TABLE messages (batch INT, idx INT, message_hash BLOB, PRIMARY KEY (batch, idx))", "CREATE TABLE privileged_transactions (batch INT PRIMARY KEY, transactions_hash BLOB)", @@ -44,6 +44,7 @@ const DB_SCHEMA: [&str; 15] = [ "CREATE TABLE batch_proofs (batch INT, prover_type INT, proof BLOB, PRIMARY KEY (batch, prover_type))", "CREATE TABLE block_signatures (block_hash BLOB PRIMARY KEY, signature BLOB)", "CREATE TABLE batch_signatures (batch INT PRIMARY KEY, signature BLOB)", + "CREATE TABLE batch_prover_input (batch INT, prover_version TEXT, prover_input BLOB, PRIMARY KEY (batch, prover_version))", ]; impl SQLStore { @@ -281,6 +282,27 @@ impl SQLStore { } Ok(()) } + + async fn store_prover_input_by_batch_and_version_in_tx( + &self, + batch_number: u64, + prover_version: &str, + prover_input: ProverInputData, + db_tx: Option<&Transaction>, + ) -> Result<(), RollupStoreError> { + let prover_input_bytes = rkyv::to_bytes::(&prover_input) + .map_err(|e| { + RollupStoreError::Custom(format!("Failed to serialize prover input: {e}")) + })? + .to_vec(); + + let queries = vec![( + "INSERT OR REPLACE INTO batch_prover_input VALUES (?1, ?2, ?3)", + (batch_number, prover_version, prover_input_bytes).into_params()?, + )]; + + self.execute_in_tx(queries, db_tx).await + } } fn read_from_row_int(row: &Row, index: i32) -> Result { @@ -580,6 +602,10 @@ impl StoreEngineRollup for SQLStore { "DELETE FROM batch_proofs WHERE batch > ?1", [batch_number].into_params()?, ), + ( + "DELETE FROM batch_prover_input WHERE batch > ?1", + [batch_number].into_params()?, + ), ]; self.execute_in_tx(queries, None).await } @@ -781,6 +807,47 @@ impl StoreEngineRollup for SQLStore { .map(|row| read_from_row_int(&row, 0)) .transpose() } + + async fn store_prover_input_by_batch_and_version( + &self, + batch_number: u64, + prover_version: &str, + prover_input: ProverInputData, + ) -> Result<(), RollupStoreError> { + self.store_prover_input_by_batch_and_version_in_tx( + batch_number, + prover_version, + prover_input, + None, + ) + .await + } + + async fn get_prover_input_by_batch_and_version( + &self, + batch_number: u64, + prover_version: &str, + ) -> Result, RollupStoreError> { + let mut rows = self + .query( + "SELECT prover_input FROM batch_prover_input WHERE batch = ?1 AND prover_version = ?2", + (batch_number, prover_version), + ) + .await?; + if let Some(row) = rows.next().await? { + let vec = read_from_row_blob(&row, 0)?; + + let prover_input = rkyv::from_bytes::(&vec) + .map_err(|e| { + RollupStoreError::Custom(format!( + "Failed to deserialize prover input for batch {batch_number} and version {prover_version}: {e}", + )) + })?; + + return Ok(Some(prover_input)); + } + Ok(None) + } } #[cfg(test)] @@ -802,6 +869,7 @@ mod tests { "batch_proofs", "block_signatures", "batch_signatures", + "batch_prover_input", ]; let mut attributes = Vec::new(); for table in tables { @@ -846,6 +914,9 @@ mod tests { ("block_signatures", "signature") => "BLOB", ("batch_signatures", "batch") => "INT", ("batch_signatures", "signature") => "BLOB", + ("batch_prover_input", "batch") => "INT", + ("batch_prover_input", "prover_version") => "TEXT", + ("batch_prover_input", "prover_input") => "BLOB", _ => { return Err(anyhow::Error::msg( "unexpected attribute {name} in table {table}", diff --git a/crates/l2/tee/quote-gen/Cargo.lock b/crates/l2/tee/quote-gen/Cargo.lock index 2f3df124901..831510407cb 100644 --- a/crates/l2/tee/quote-gen/Cargo.lock +++ b/crates/l2/tee/quote-gen/Cargo.lock @@ -2071,7 +2071,7 @@ dependencies = [ [[package]] name = "ethrex-blockchain" -version = "3.0.0" +version = "4.0.0" dependencies = [ "bytes", "ethrex-common", @@ -2089,7 +2089,7 @@ dependencies = [ [[package]] name = "ethrex-common" -version = "3.0.0" +version = "4.0.0" dependencies = [ "bytes", "crc32fast", @@ -2117,7 +2117,7 @@ dependencies = [ [[package]] name = "ethrex-config" -version = "3.0.0" +version = "4.0.0" dependencies = [ "ethrex-common", "ethrex-p2p", @@ -2128,7 +2128,7 @@ dependencies = [ [[package]] name = "ethrex-crypto" -version = "3.0.0" +version = "4.0.0" dependencies = [ "c-kzg", "kzg-rs", @@ -2137,7 +2137,7 @@ dependencies = [ [[package]] name = "ethrex-dev" -version = "3.0.0" +version = "4.0.0" dependencies = [ "bytes", "envy", @@ -2156,7 +2156,7 @@ dependencies = [ [[package]] name = "ethrex-l2" -version = "3.0.0" +version = "4.0.0" dependencies = [ "aligned-sdk", "axum", @@ -2213,7 +2213,7 @@ dependencies = [ [[package]] name = "ethrex-l2-common" -version = "3.0.0" +version = "4.0.0" dependencies = [ "bytes", "ethereum-types 0.15.1", @@ -2223,15 +2223,17 @@ dependencies = [ "ethrex-trie", "ethrex-vm", "lambdaworks-crypto 0.11.0", + "rkyv", "secp256k1", "serde", + "serde_with", "sha3", "thiserror 2.0.16", ] [[package]] name = "ethrex-l2-rpc" -version = "3.0.0" +version = "4.0.0" dependencies = [ "axum", "bytes", @@ -2260,11 +2262,12 @@ dependencies = [ [[package]] name = "ethrex-levm" -version = "3.0.0" +version = "4.0.0" dependencies = [ "ark-bn254", "ark-ec", "ark-ff", + "bitvec", "bls12_381", "bytes", "datatest-stable", @@ -2290,7 +2293,7 @@ dependencies = [ [[package]] name = "ethrex-metrics" -version = "3.0.0" +version = "4.0.0" dependencies = [ "ethrex-common", "serde", @@ -2301,7 +2304,7 @@ dependencies = [ [[package]] name = "ethrex-p2p" -version = "3.0.0" +version = "4.0.0" dependencies = [ "aes", "async-trait", @@ -2342,7 +2345,7 @@ dependencies = [ [[package]] name = "ethrex-rlp" -version = "3.0.0" +version = "4.0.0" dependencies = [ "bytes", "ethereum-types 0.15.1", @@ -2355,7 +2358,7 @@ dependencies = [ [[package]] name = "ethrex-rpc" -version = "3.0.0" +version = "4.0.0" dependencies = [ "axum", "axum-extra", @@ -2389,7 +2392,7 @@ dependencies = [ [[package]] name = "ethrex-sdk" -version = "3.0.0" +version = "4.0.0" dependencies = [ "bytes", "ethereum-types 0.15.1", @@ -2414,7 +2417,7 @@ dependencies = [ [[package]] name = "ethrex-sdk-contract-utils" -version = "3.0.0" +version = "4.0.0" dependencies = [ "thiserror 2.0.16", "tracing", @@ -2422,7 +2425,7 @@ dependencies = [ [[package]] name = "ethrex-storage" -version = "3.0.0" +version = "4.0.0" dependencies = [ "anyhow", "async-trait", @@ -2442,7 +2445,7 @@ dependencies = [ [[package]] name = "ethrex-storage-rollup" -version = "3.0.0" +version = "4.0.0" dependencies = [ "anyhow", "async-trait", @@ -2454,6 +2457,7 @@ dependencies = [ "ethrex-storage", "ethrex-trie", "futures", + "rkyv", "thiserror 2.0.16", "tracing", ] @@ -2467,7 +2471,7 @@ dependencies = [ [[package]] name = "ethrex-trie" -version = "3.0.0" +version = "4.0.0" dependencies = [ "anyhow", "bytes", @@ -2488,7 +2492,7 @@ dependencies = [ [[package]] name = "ethrex-vm" -version = "3.0.0" +version = "4.0.0" dependencies = [ "bincode", "bytes", @@ -2865,7 +2869,7 @@ dependencies = [ [[package]] name = "guest_program" -version = "3.0.0" +version = "4.0.0" dependencies = [ "bytes", "ethrex-blockchain", diff --git a/crates/l2/tee/quote-gen/src/main.rs b/crates/l2/tee/quote-gen/src/main.rs index f48ac2c51e0..ece7155f3a6 100644 --- a/crates/l2/tee/quote-gen/src/main.rs +++ b/crates/l2/tee/quote-gen/src/main.rs @@ -3,7 +3,7 @@ mod sender; use configfs_tsm::create_tdx_quote; use ethrex_common::Bytes; use ethrex_common::utils::keccak; -use ethrex_l2::sequencer::proof_coordinator::get_commit_hash; +use ethrex_l2::sequencer::utils::get_git_commit_hash; use ethrex_l2_common::{ calldata::Value, prover::{BatchProof, ProofCalldata, ProverType}, @@ -82,7 +82,7 @@ async fn setup(private_key: &SecretKey) -> Result<(), String> { #[tokio::main] async fn main() { let (private_key, _) = generate_keypair(&mut rand::rngs::OsRng); - let commit_hash = get_commit_hash(); + let commit_hash = get_git_commit_hash(); while let Err(err) = setup(&private_key).await { println!("Error sending quote: {}", err); sleep(Duration::from_millis(POLL_INTERVAL_MS)).await;