diff --git a/core/bin/zksync_tee_prover/src/api_client.rs b/core/bin/zksync_tee_prover/src/api_client.rs index 1530da971157..ced92f8228f9 100644 --- a/core/bin/zksync_tee_prover/src/api_client.rs +++ b/core/bin/zksync_tee_prover/src/api_client.rs @@ -9,7 +9,7 @@ use zksync_prover_interface::{ SubmitTeeProofResponse, TeeProofGenerationDataRequest, TeeProofGenerationDataResponse, }, inputs::TeeVerifierInput, - outputs::L1BatchTeeProofForL1, + L1BatchTeeProofForL1, }; use zksync_types::{tee_types::TeeType, L1BatchNumber}; @@ -74,17 +74,21 @@ impl TeeApiClient { /// Fetches the next job for the TEE prover to process, verifying and signing it if the /// verification is successful. - pub async fn get_job(&self) -> Result>, TeeProverError> { - let request = TeeProofGenerationDataRequest {}; + pub async fn get_job( + &self, + tee_type: TeeType, + ) -> Result>, TeeProverError> { + let request = TeeProofGenerationDataRequest { tee_type }; let response = self .post::<_, TeeProofGenerationDataResponse, _>("/tee/proof_inputs", request) .await?; - Ok(response.0) + Ok(response) } /// Submits the successfully verified proof to the TEE prover interface API. pub async fn submit_proof( &self, + proof_id: i64, batch_number: L1BatchNumber, signature: Signature, pubkey: &PublicKey, @@ -92,6 +96,7 @@ impl TeeApiClient { tee_type: TeeType, ) -> Result<(), TeeProverError> { let request = SubmitTeeProofRequest(Box::new(L1BatchTeeProofForL1 { + proof_id, signature: signature.serialize_compact().into(), pubkey: pubkey.serialize().into(), proof: root_hash.as_bytes().into(), diff --git a/core/bin/zksync_tee_prover/src/tee_prover.rs b/core/bin/zksync_tee_prover/src/tee_prover.rs index b14d07b72db6..4a7f2e4676f2 100644 --- a/core/bin/zksync_tee_prover/src/tee_prover.rs +++ b/core/bin/zksync_tee_prover/src/tee_prover.rs @@ -112,11 +112,12 @@ impl TeeProver { } async fn step(&self) -> Result, TeeProverError> { - match self.api_client.get_job().await? { + match self.api_client.get_job(self.tee_type).await? { Some(job) => { - let (signature, batch_number, root_hash) = self.verify(*job)?; + let (signature, batch_number, root_hash) = self.verify(*job.input)?; self.api_client .submit_proof( + job.proof_id.unwrap(), // TODO unwrap() is not safe here batch_number, signature, &self.public_key, diff --git a/core/lib/dal/.sqlx/query-184573db68b82c15ad5a647b4784b4a0c11d0a45774fade80e88cb902104fe28.json b/core/lib/dal/.sqlx/query-184573db68b82c15ad5a647b4784b4a0c11d0a45774fade80e88cb902104fe28.json new file mode 100644 index 000000000000..07e25f505a6f --- /dev/null +++ b/core/lib/dal/.sqlx/query-184573db68b82c15ad5a647b4784b4a0c11d0a45774fade80e88cb902104fe28.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n proofs.l1_batch_number\n FROM\n tee_proofs AS proofs\n JOIN tee_verifier_input_producer_jobs AS inputs\n ON proofs.l1_batch_number = inputs.l1_batch_number\n WHERE\n inputs.status = 'Successful'\n AND proofs.prover_taken_at IS NULL\n ORDER BY\n proofs.l1_batch_number ASC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "184573db68b82c15ad5a647b4784b4a0c11d0a45774fade80e88cb902104fe28" +} diff --git a/core/lib/dal/.sqlx/query-1ef09a1df23f8dea9779f34350b38dbd01af9068af4059b53fe79a6f2505b0a5.json b/core/lib/dal/.sqlx/query-1ef09a1df23f8dea9779f34350b38dbd01af9068af4059b53fe79a6f2505b0a5.json new file mode 100644 index 000000000000..3d5bd64e3a57 --- /dev/null +++ b/core/lib/dal/.sqlx/query-1ef09a1df23f8dea9779f34350b38dbd01af9068af4059b53fe79a6f2505b0a5.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE tee_proofs\n SET\n pubkey = $1,\n signature = $2,\n proof = $3,\n proved_at = NOW()\n WHERE\n id = $4\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Bytea", + "Bytea", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "1ef09a1df23f8dea9779f34350b38dbd01af9068af4059b53fe79a6f2505b0a5" +} diff --git a/core/lib/dal/.sqlx/query-7b11e9d71ba1b19a4976e574286304afac6fc7b4c3e5bed2ff4f7da248523e33.json b/core/lib/dal/.sqlx/query-7b11e9d71ba1b19a4976e574286304afac6fc7b4c3e5bed2ff4f7da248523e33.json new file mode 100644 index 000000000000..fdab20788c36 --- /dev/null +++ b/core/lib/dal/.sqlx/query-7b11e9d71ba1b19a4976e574286304afac6fc7b4c3e5bed2ff4f7da248523e33.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n proofs.l1_batch_number\n FROM\n tee_proofs AS proofs\n JOIN tee_verifier_input_producer_jobs AS inputs ON proofs.l1_batch_number = inputs.l1_batch_number\n WHERE\n inputs.status = 'Successful'\n AND proofs.prover_taken_at IS NULL\n ORDER BY\n proofs.l1_batch_number ASC\n LIMIT\n 1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "7b11e9d71ba1b19a4976e574286304afac6fc7b4c3e5bed2ff4f7da248523e33" +} diff --git a/core/lib/dal/.sqlx/query-94eefcf763d8a4bc6a6c1860be17042743766d7fc2c231bb699bef005b81a7fc.json b/core/lib/dal/.sqlx/query-94eefcf763d8a4bc6a6c1860be17042743766d7fc2c231bb699bef005b81a7fc.json new file mode 100644 index 000000000000..fb5ec089514b --- /dev/null +++ b/core/lib/dal/.sqlx/query-94eefcf763d8a4bc6a6c1860be17042743766d7fc2c231bb699bef005b81a7fc.json @@ -0,0 +1,29 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE tee_proofs\n SET\n prover_taken_at = NOW()\n WHERE\n id = (\n SELECT\n proofs.id\n FROM\n tee_proofs AS proofs\n JOIN tee_verifier_input_producer_jobs AS inputs ON proofs.l1_batch_number = inputs.l1_batch_number\n WHERE\n inputs.status = 'Successful'\n AND proofs.tee_type = $1\n AND (\n proofs.prover_taken_at IS NULL\n OR proofs.prover_taken_at < NOW() - $2::INTERVAL\n )\n ORDER BY\n tee_proofs.l1_batch_number ASC,\n proofs.prover_taken_at ASC NULLS FIRST\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n tee_proofs.id,\n tee_proofs.l1_batch_number\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "l1_batch_number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text", + "Interval" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "94eefcf763d8a4bc6a6c1860be17042743766d7fc2c231bb699bef005b81a7fc" +} diff --git a/core/lib/dal/.sqlx/query-eddef3ecd6cdc205e91ae9ceaa23521353d37863bad59cc4c364b83d02e63db1.json b/core/lib/dal/.sqlx/query-eddef3ecd6cdc205e91ae9ceaa23521353d37863bad59cc4c364b83d02e63db1.json new file mode 100644 index 000000000000..0db3c5ca1b1d --- /dev/null +++ b/core/lib/dal/.sqlx/query-eddef3ecd6cdc205e91ae9ceaa23521353d37863bad59cc4c364b83d02e63db1.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO\n tee_proofs (l1_batch_number, tee_type, created_at)\n VALUES\n ($1, $2, NOW())\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Text" + ] + }, + "nullable": [] + }, + "hash": "eddef3ecd6cdc205e91ae9ceaa23521353d37863bad59cc4c364b83d02e63db1" +} diff --git a/core/lib/dal/doc/ProofGenerationDal.md b/core/lib/dal/doc/ProofGenerationDal.md deleted file mode 100644 index 618fdfba13b0..000000000000 --- a/core/lib/dal/doc/ProofGenerationDal.md +++ /dev/null @@ -1,22 +0,0 @@ -# ProofGenerationDal - -## Table Name - -proof_generation_details - -## `status` Diagram - -```mermaid ---- -title: Status Diagram ---- -stateDiagram-v2 -[*] --> ready_to_be_proven : insert_proof_generation_details -ready_to_be_proven --> picked_by_prover : get_next_block_to_be_proven -picked_by_prover --> generated : save_proof_artifacts_metadata -generated --> [*] - -[*] --> skipped : mark_proof_generation_job_as_skipped -skipped --> [*] - -``` diff --git a/core/lib/dal/migrations/20240325133100_add_tee_verifier_input_producer_jobs_table.down.sql b/core/lib/dal/migrations/20240325133100_add_tee_verifier_input_producer_jobs_table.down.sql index 2d4d6a6ad7a7..bccd4f97dcbb 100644 --- a/core/lib/dal/migrations/20240325133100_add_tee_verifier_input_producer_jobs_table.down.sql +++ b/core/lib/dal/migrations/20240325133100_add_tee_verifier_input_producer_jobs_table.down.sql @@ -1,4 +1,5 @@ DROP INDEX IF EXISTS idx_tee_verifier_input_producer_jobs_status_processing_attempts; +DROP INDEX IF EXISTS idx_tee_verifier_input_producer_jobs_l1_batch_number_status; DROP TABLE IF EXISTS tee_verifier_input_producer_jobs; diff --git a/core/lib/dal/migrations/20240325143100_add_tee_verifier_input_producer_jobs_table.up.sql b/core/lib/dal/migrations/20240325143100_add_tee_verifier_input_producer_jobs_table.up.sql index eb34068f876d..26e7e5a11940 100644 --- a/core/lib/dal/migrations/20240325143100_add_tee_verifier_input_producer_jobs_table.up.sql +++ b/core/lib/dal/migrations/20240325143100_add_tee_verifier_input_producer_jobs_table.up.sql @@ -5,7 +5,6 @@ CREATE TABLE IF NOT EXISTS tee_verifier_input_producer_jobs l1_batch_number BIGINT NOT NULL PRIMARY KEY, attempts SMALLINT NOT NULL DEFAULT 0, status tee_verifier_input_producer_job_status, - picked_by TEXT, input_blob_url TEXT, error TEXT, created_at TIMESTAMP NOT NULL, @@ -16,3 +15,6 @@ CREATE TABLE IF NOT EXISTS tee_verifier_input_producer_jobs CREATE INDEX IF NOT EXISTS idx_tee_verifier_input_producer_jobs_status_processing_attempts ON tee_verifier_input_producer_jobs (status, processing_started_at, attempts); + +CREATE INDEX IF NOT EXISTS idx_tee_verifier_input_producer_jobs_l1_batch_number_status +ON tee_verifier_input_producer_jobs (l1_batch_number, status); diff --git a/core/lib/dal/migrations/20240523085604_add_tee_proof_generation_details_table.down.sql b/core/lib/dal/migrations/20240523085604_add_tee_proof_generation_details_table.down.sql index 5b4f9958a8ea..d46bc4aa154d 100644 --- a/core/lib/dal/migrations/20240523085604_add_tee_proof_generation_details_table.down.sql +++ b/core/lib/dal/migrations/20240523085604_add_tee_proof_generation_details_table.down.sql @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS tee_attestations; -DROP TABLE IF EXISTS tee_proof_generation_details; +DROP INDEX IF EXISTS idx_proofs_number_per_batch_number_and_tee_type; -DROP INDEX IF EXISTS idx_tee_proof_generation_details_status_prover_taken_at; +DROP TABLE IF EXISTS tee_attestations; +DROP TABLE IF EXISTS tee_proofs; diff --git a/core/lib/dal/migrations/20240523085604_add_tee_proof_generation_details_table.up.sql b/core/lib/dal/migrations/20240523085604_add_tee_proof_generation_details_table.up.sql index 3a249c44346c..013bdcd02b17 100644 --- a/core/lib/dal/migrations/20240523085604_add_tee_proof_generation_details_table.up.sql +++ b/core/lib/dal/migrations/20240523085604_add_tee_proof_generation_details_table.up.sql @@ -4,19 +4,18 @@ CREATE TABLE IF NOT EXISTS tee_attestations attestation BYTEA ); -CREATE TABLE IF NOT EXISTS tee_proof_generation_details +CREATE TABLE IF NOT EXISTS tee_proofs ( - l1_batch_number BIGINT PRIMARY KEY REFERENCES tee_verifier_input_producer_jobs (l1_batch_number) ON DELETE CASCADE, - status TEXT NOT NULL, + id BIGSERIAL PRIMARY KEY, + l1_batch_number BIGINT NOT NULL REFERENCES tee_verifier_input_producer_jobs (l1_batch_number) ON DELETE CASCADE, + tee_type TEXT NOT NULL, + pubkey BYTEA REFERENCES tee_attestations (pubkey) ON DELETE CASCADE, signature BYTEA, - pubkey BYTEA REFERENCES tee_attestations (pubkey) ON DELETE SET NULL, proof BYTEA, - tee_type TEXT, created_at TIMESTAMP NOT NULL, - updated_at TIMESTAMP NOT NULL, + proved_at TIMESTAMP, prover_taken_at TIMESTAMP ); -CREATE INDEX IF NOT EXISTS idx_tee_proof_generation_details_status_prover_taken_at - ON tee_proof_generation_details (prover_taken_at) - WHERE status = 'picked_by_prover'; +CREATE INDEX IF NOT EXISTS idx_proofs_number_per_batch_number_and_tee_type + ON tee_proofs (l1_batch_number, tee_type); diff --git a/core/lib/dal/src/models/mod.rs b/core/lib/dal/src/models/mod.rs index 1e852e3f6364..d22541620f2a 100644 --- a/core/lib/dal/src/models/mod.rs +++ b/core/lib/dal/src/models/mod.rs @@ -11,6 +11,7 @@ pub mod storage_log; pub mod storage_oracle_info; pub mod storage_protocol_version; pub mod storage_sync; +pub mod storage_tee_proof; pub mod storage_transaction; pub mod storage_verification_request; pub mod storage_witness_job_info; diff --git a/core/lib/dal/src/models/storage_tee_proof.rs b/core/lib/dal/src/models/storage_tee_proof.rs new file mode 100644 index 000000000000..9c55c86eb26d --- /dev/null +++ b/core/lib/dal/src/models/storage_tee_proof.rs @@ -0,0 +1,35 @@ +use serde::{Deserialize, Serialize}; // TODO needed? +use zksync_types::{tee_types::TeeType, L1BatchNumber}; + +/// Represents a proof generated within a TEE enclave +/// TODO move it to core/lib/types/src/api/mod.rs and call TeeProof? +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct StorageTeeProof { + // batch number for which the proof was generated + pub l1_batch_number: L1BatchNumber, + // type of TEE used for attestation + pub tee_type: Option, + // pubkey used for signature verification; each key pair is attested by the TEE attestation + // stored in the db + pub pubkey: Option>, + // signature generated within the TEE enclave, using the privkey corresponding to the pubkey + pub signature: Option>, + // data that was signed + pub proof: Option>, + // attestation quote generated within the TEE enclave + pub attestation: Option>, + // timestamp when the proof was generated + pub proved_at: chrono::DateTime, +} + +/// TODO rename it TeeProof once StorageTeeProof is moved to api/mod.rs? +#[derive(Debug, Clone, sqlx::FromRow)] +pub struct TmpStorageTeeProof { + #[allow(dead_code)] + pub id: i64, + pub pubkey: Option>, + pub signature: Option>, + pub proof: Option>, + pub proved_at: chrono::DateTime, + pub attestation: Option>, +} diff --git a/core/lib/dal/src/proof_generation_dal.rs b/core/lib/dal/src/proof_generation_dal.rs index 4e37cc644f8e..0c857d929fe9 100644 --- a/core/lib/dal/src/proof_generation_dal.rs +++ b/core/lib/dal/src/proof_generation_dal.rs @@ -1,4 +1,3 @@ -#![doc = include_str!("../doc/ProofGenerationDal.md")] use std::time::Duration; use strum::{Display, EnumString}; diff --git a/core/lib/dal/src/tee_proof_generation_dal.rs b/core/lib/dal/src/tee_proof_generation_dal.rs index e93743781f87..f0ebc7720523 100644 --- a/core/lib/dal/src/tee_proof_generation_dal.rs +++ b/core/lib/dal/src/tee_proof_generation_dal.rs @@ -1,130 +1,101 @@ use std::time::Duration; -use serde::{Deserialize, Serialize}; -use strum::{Display, EnumString}; use zksync_db_connection::{ - connection::Connection, - error::DalResult, - instrument::{InstrumentExt, Instrumented}, + connection::Connection, error::DalResult, instrument::Instrumented, utils::pg_interval_from_duration, }; use zksync_types::{tee_types::TeeType, L1BatchNumber}; -use crate::Core; +use crate::{ + models::storage_tee_proof::{StorageTeeProof, TmpStorageTeeProof}, + Core, +}; #[derive(Debug)] pub struct TeeProofGenerationDal<'a, 'c> { pub(crate) storage: &'a mut Connection<'c, Core>, } -#[derive(Debug, Serialize, Deserialize)] -pub struct TeeProof { - // signature generated within the TEE enclave, using the privkey corresponding to the pubkey - pub signature: Option>, - // pubkey used for signature verification; each key pair is attested by the TEE attestation - // stored in the db - pub pubkey: Option>, - // data that was signed - pub proof: Option>, - // type of TEE used for attestation - pub tee_type: Option, -} - -#[derive(Debug, EnumString, Display)] -enum TeeProofGenerationJobStatus { - #[strum(serialize = "ready_to_be_proven")] - ReadyToBeProven, - #[strum(serialize = "picked_by_prover")] - PickedByProver, - #[strum(serialize = "generated")] - Generated, - #[strum(serialize = "skipped")] - Skipped, -} - impl TeeProofGenerationDal<'_, '_> { - pub async fn get_next_block_to_be_proven( + pub async fn get_next_batch_to_be_proven( &mut self, + tee_type: TeeType, processing_timeout: Duration, - ) -> DalResult> { + ) -> DalResult> { let processing_timeout = pg_interval_from_duration(processing_timeout); let query = sqlx::query!( r#" - UPDATE tee_proof_generation_details + UPDATE tee_proofs SET - status = 'picked_by_prover', - updated_at = NOW(), prover_taken_at = NOW() WHERE - l1_batch_number = ( + id = ( SELECT - proofs.l1_batch_number + proofs.id FROM - tee_proof_generation_details AS proofs + tee_proofs AS proofs JOIN tee_verifier_input_producer_jobs AS inputs ON proofs.l1_batch_number = inputs.l1_batch_number WHERE inputs.status = 'Successful' + AND proofs.tee_type = $1 AND ( - proofs.status = 'ready_to_be_proven' - OR ( - proofs.status = 'picked_by_prover' - AND proofs.prover_taken_at < NOW() - $1::INTERVAL - ) + proofs.prover_taken_at IS NULL + OR proofs.prover_taken_at < NOW() - $2::INTERVAL ) ORDER BY - l1_batch_number ASC + tee_proofs.l1_batch_number ASC, + proofs.prover_taken_at ASC NULLS FIRST LIMIT 1 FOR UPDATE SKIP LOCKED ) RETURNING - tee_proof_generation_details.l1_batch_number + tee_proofs.id, + tee_proofs.l1_batch_number "#, + &tee_type.to_string(), &processing_timeout, ); - let batch_number = Instrumented::new("get_next_block_to_be_proven") + let batch_number = Instrumented::new("get_next_batch_to_be_proven") + .with_arg("tee_type", &tee_type) .with_arg("processing_timeout", &processing_timeout) .with(query) .fetch_optional(self.storage) .await? - .map(|row| L1BatchNumber(row.l1_batch_number as u32)); + .map(|row| (row.id as i64, L1BatchNumber(row.l1_batch_number as u32))); Ok(batch_number) } pub async fn save_proof_artifacts_metadata( &mut self, - block_number: L1BatchNumber, - signature: &[u8], + proof_id: i64, pubkey: &[u8], + signature: &[u8], proof: &[u8], - tee_type: TeeType, ) -> DalResult<()> { let query = sqlx::query!( r#" - UPDATE tee_proof_generation_details + UPDATE tee_proofs SET - status = 'generated', - signature = $1, - pubkey = $2, + pubkey = $1, + signature = $2, proof = $3, - tee_type = $4, - updated_at = NOW() + proved_at = NOW() WHERE - l1_batch_number = $5 + id = $4 "#, - signature, pubkey, + signature, proof, - tee_type.to_string(), - i64::from(block_number.0) + proof_id ); let instrumentation = Instrumented::new("save_proof_artifacts_metadata") - .with_arg("signature", &signature) .with_arg("pubkey", &pubkey) + .with_arg("signature", &signature) .with_arg("proof", &proof) - .with_arg("tee_type", &tee_type); + .with_arg("proof_id", &proof_id); let result = instrumentation .clone() .with(query) @@ -132,7 +103,8 @@ impl TeeProofGenerationDal<'_, '_> { .await?; if result.rows_affected() == 0 { let err = instrumentation.constraint_error(anyhow::anyhow!( - "Updating TEE proof for a non-existent batch number is not allowed" + "Updating TEE proof for a non-existent ID {} is not allowed", + proof_id )); return Err(err); } @@ -142,39 +114,52 @@ impl TeeProofGenerationDal<'_, '_> { pub async fn insert_tee_proof_generation_job( &mut self, - block_number: L1BatchNumber, + batch_number: L1BatchNumber, + tee_type: TeeType, ) -> DalResult<()> { - let block_number = i64::from(block_number.0); - sqlx::query!( + let batch_number = i64::from(batch_number.0); + let query = sqlx::query!( r#" INSERT INTO - tee_proof_generation_details (l1_batch_number, status, created_at, updated_at) + tee_proofs (l1_batch_number, tee_type, created_at) VALUES - ($1, 'ready_to_be_proven', NOW(), NOW()) - ON CONFLICT (l1_batch_number) DO NOTHING + ($1, $2, NOW()) "#, - block_number, - ) - .instrument("create_tee_proof_generation_details") - .with_arg("l1_batch_number", &block_number) - .report_latency() - .execute(self.storage) - .await?; + batch_number, + tee_type.to_string(), + ); + let instrumentation = Instrumented::new("insert_tee_proof_generation_job") + .with_arg("l1_batch_number", &batch_number) + .with_arg("tee_type", &tee_type); + let result = instrumentation + .clone() + .with(query) + .execute(self.storage) + .await?; + if result.rows_affected() == 0 { + let err = instrumentation.constraint_error(anyhow::anyhow!( + "Unable to insert TEE proof for {}, {}", + batch_number, + tee_type + )); + return Err(err); + } Ok(()) } + #[cfg(test)] pub async fn get_oldest_unpicked_batch(&mut self) -> DalResult> { let query = sqlx::query!( r#" SELECT proofs.l1_batch_number FROM - tee_proof_generation_details AS proofs + tee_proofs AS proofs JOIN tee_verifier_input_producer_jobs AS inputs ON proofs.l1_batch_number = inputs.l1_batch_number WHERE inputs.status = 'Successful' - AND proofs.status = 'ready_to_be_proven' + AND proofs.prover_taken_at IS NULL ORDER BY proofs.l1_batch_number ASC LIMIT @@ -220,38 +205,49 @@ impl TeeProofGenerationDal<'_, '_> { Ok(()) } - pub async fn get_tee_proof( + pub async fn get_tee_proofs( &mut self, - block_number: L1BatchNumber, - ) -> DalResult> { - let query = sqlx::query!( + batch_number: L1BatchNumber, + tee_type: Option, + ) -> DalResult> { + let query = format!( r#" SELECT - signature, - pubkey, - proof, - tee_type + tp.id, + tp.pubkey, + tp.signature, + tp.proof, + tp.proved_at, + ta.attestation FROM - tee_proof_generation_details + tee_proofs tp + LEFT JOIN + tee_attestations ta ON tp.pubkey = ta.pubkey WHERE - l1_batch_number = $1 + tp.l1_batch_number = {} + {} + ORDER BY tp.id "#, - i64::from(block_number.0) + i64::from(batch_number.0), + tee_type.map_or_else(String::new, |tt| format!("AND tp.tee_type = '{}'", tt)) ); - let proof = Instrumented::new("get_tee_proof") - .with_arg("l1_batch_number", &block_number) - .with(query) - .fetch_optional(self.storage) - .await? - .map(|row| TeeProof { - signature: row.signature, + + let proofs: Vec = sqlx::query_as(&query) + .fetch_all(self.storage.conn()) + .await + .unwrap() + .into_iter() + .map(|row: TmpStorageTeeProof| StorageTeeProof { + l1_batch_number: batch_number, + tee_type, pubkey: row.pubkey, + signature: row.signature, proof: row.proof, - tee_type: row - .tee_type - .map(|tt| tt.parse::().expect("Invalid TEE type")), - }); + attestation: row.attestation, + proved_at: row.proved_at, + }) + .collect(); - Ok(proof) + Ok(proofs) } } diff --git a/core/lib/prover_interface/src/api.rs b/core/lib/prover_interface/src/api.rs index 00ac85a40739..6f937d6ab91b 100644 --- a/core/lib/prover_interface/src/api.rs +++ b/core/lib/prover_interface/src/api.rs @@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize}; use zksync_types::{ protocol_version::{L1VerifierConfig, ProtocolSemanticVersion}, + tee_types::TeeType, L1BatchNumber, }; @@ -29,7 +30,10 @@ pub enum ProofGenerationDataResponse { } #[derive(Debug, Serialize, Deserialize)] -pub struct TeeProofGenerationDataResponse(pub Option>); +pub struct TeeProofGenerationDataResponse { + pub proof_id: Option, + pub input: Option>, +} #[derive(Debug, Serialize, Deserialize)] pub enum SubmitProofResponse { @@ -52,7 +56,10 @@ pub enum RegisterTeeAttestationResponse { #[derive(Debug, Serialize, Deserialize)] pub struct ProofGenerationDataRequest {} -pub type TeeProofGenerationDataRequest = ProofGenerationDataRequest; +#[derive(Debug, Serialize, Deserialize)] +pub struct TeeProofGenerationDataRequest { + pub tee_type: TeeType, +} #[derive(Debug, Serialize, Deserialize)] pub enum SubmitProofRequest { diff --git a/core/lib/prover_interface/src/outputs.rs b/core/lib/prover_interface/src/outputs.rs index 9672bfb2142b..8a4bd8e47405 100644 --- a/core/lib/prover_interface/src/outputs.rs +++ b/core/lib/prover_interface/src/outputs.rs @@ -16,6 +16,8 @@ pub struct L1BatchProofForL1 { /// A "final" TEE proof that can be sent to the L1 contract. #[derive(Clone, PartialEq, Serialize, Deserialize)] pub struct L1BatchTeeProofForL1 { + // ID of the proof in the database to distinguish between different proofs for the same batch + pub proof_id: i64, // signature generated within the TEE enclave, using the privkey corresponding to the pubkey pub signature: Vec, // pubkey used for signature verification; each key pair is attested by the TEE attestation diff --git a/core/lib/prover_interface/tests/job_serialization.rs b/core/lib/prover_interface/tests/job_serialization.rs index a2d55a140655..81b969d5d13e 100644 --- a/core/lib/prover_interface/tests/job_serialization.rs +++ b/core/lib/prover_interface/tests/job_serialization.rs @@ -167,6 +167,7 @@ fn test_proof_request_serialization() { #[test] fn test_tee_proof_request_serialization() { let tee_proof_str = r#"{ + "proof_id": 0, "signature": [ 0, 1, 2, 3, 4 ], "pubkey": [ 5, 6, 7, 8, 9 ], "proof": [ 10, 11, 12, 13, 14 ], @@ -174,6 +175,7 @@ fn test_tee_proof_request_serialization() { }"#; let tee_proof_result = serde_json::from_str::(tee_proof_str).unwrap(); let tee_proof_expected = SubmitTeeProofRequest(Box::new(L1BatchTeeProofForL1 { + proof_id: 0, signature: vec![0, 1, 2, 3, 4], pubkey: vec![5, 6, 7, 8, 9], proof: vec![10, 11, 12, 13, 14], diff --git a/core/node/proof_data_handler/src/lib.rs b/core/node/proof_data_handler/src/lib.rs index 50643e7add1f..618a786ea658 100644 --- a/core/node/proof_data_handler/src/lib.rs +++ b/core/node/proof_data_handler/src/lib.rs @@ -1,11 +1,7 @@ use std::{net::SocketAddr, sync::Arc}; use anyhow::Context as _; -use axum::{ - extract::Path, - routing::{get, post}, - Json, Router, -}; +use axum::{extract::Path, routing::post, Json, Router}; use request_processor::RequestProcessor; use tee_request_processor::TeeRequestProcessor; use tokio::sync::watch; @@ -95,7 +91,6 @@ fn create_proof_processing_router( TeeRequestProcessor::new(blob_store, connection_pool, config.clone()); let submit_tee_proof_processor = get_tee_proof_gen_processor.clone(); let register_tee_attestation_processor = get_tee_proof_gen_processor.clone(); - let get_tee_proof_processor = get_tee_proof_gen_processor.clone(); router = router.route( "/tee/proof_inputs", @@ -126,15 +121,6 @@ fn create_proof_processing_router( .await }, ), - ) - .route("/tee/get_proof/:l1_batch_number", - get( - move |l1_batch_number: Path| async move { - get_tee_proof_processor - .get_proof(l1_batch_number) - .await - }, - ) ); } diff --git a/core/node/proof_data_handler/src/tee_request_processor.rs b/core/node/proof_data_handler/src/tee_request_processor.rs index 686d500b9eb4..20613ba909e2 100644 --- a/core/node/proof_data_handler/src/tee_request_processor.rs +++ b/core/node/proof_data_handler/src/tee_request_processor.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use axum::{extract::Path, Json}; use zksync_config::configs::ProofDataHandlerConfig; -use zksync_dal::{tee_proof_generation_dal::TeeProof, ConnectionPool, Core, CoreDal}; +use zksync_dal::{ConnectionPool, Core, CoreDal}; use zksync_object_store::ObjectStore; use zksync_prover_interface::{ api::{ @@ -49,12 +49,19 @@ impl TeeRequestProcessor { let l1_batch_number_result = connection .tee_proof_generation_dal() - .get_next_block_to_be_proven(self.config.proof_generation_timeout()) + .get_next_batch_to_be_proven(request.tee_type, self.config.proof_generation_timeout()) .await .map_err(RequestProcessorError::Dal)?; - let l1_batch_number = match l1_batch_number_result { - Some(number) => number, - None => return Ok(Json(TeeProofGenerationDataResponse(None))), + + let (proof_id, l1_batch_number) = match l1_batch_number_result { + Some((proof_id, number)) => (proof_id, number), + None => { + // TODO introduce a proper type + return Ok(Json(TeeProofGenerationDataResponse { + proof_id: None, + input: None, + })); + } }; let tee_verifier_input: TeeVerifierInput = self @@ -63,9 +70,12 @@ impl TeeRequestProcessor { .await .map_err(RequestProcessorError::ObjectStore)?; - Ok(Json(TeeProofGenerationDataResponse(Some(Box::new( - tee_verifier_input, - ))))) + let response = TeeProofGenerationDataResponse { + proof_id: Some(proof_id), + input: Some(Box::new(tee_verifier_input)), + }; + + Ok(Json(response)) } pub(crate) async fn submit_proof( @@ -82,16 +92,15 @@ impl TeeRequestProcessor { let mut dal = connection.tee_proof_generation_dal(); tracing::info!( - "Received proof {:?} for block number: {:?}", + "Received proof {:?} for batch number: {:?}", proof, l1_batch_number ); dal.save_proof_artifacts_metadata( - l1_batch_number, - &proof.0.signature, + proof.0.proof_id, &proof.0.pubkey, + &proof.0.signature, &proof.0.proof, - proof.0.tee_type, ) .await .map_err(RequestProcessorError::Dal)?; @@ -118,23 +127,4 @@ impl TeeRequestProcessor { Ok(Json(RegisterTeeAttestationResponse::Success)) } - - pub(crate) async fn get_proof( - &self, - Path(l1_batch_number): Path, - ) -> Result, RequestProcessorError> { - let mut connection = self - .pool - .connection() - .await - .map_err(RequestProcessorError::Dal)?; - let mut dal = connection.tee_proof_generation_dal(); - let l1_batch_number = L1BatchNumber(l1_batch_number); - let tee_proof = dal - .get_tee_proof(l1_batch_number) - .await - .map_err(RequestProcessorError::Dal)?; - - Ok(Json(tee_proof.unwrap())) - } } diff --git a/core/node/tee_verifier_input_producer/src/lib.rs b/core/node/tee_verifier_input_producer/src/lib.rs index 0cd28ee5ce79..abd70542a42f 100644 --- a/core/node/tee_verifier_input_producer/src/lib.rs +++ b/core/node/tee_verifier_input_producer/src/lib.rs @@ -19,7 +19,7 @@ use zksync_prover_interface::inputs::{ }; use zksync_queued_job_processor::JobProcessor; use zksync_tee_verifier::Verify; -use zksync_types::{L1BatchNumber, L2ChainId}; +use zksync_types::{tee_types::TeeType, L1BatchNumber, L2ChainId}; use zksync_utils::u256_to_h256; use zksync_vm_utils::storage::L1BatchParamsProvider; @@ -241,7 +241,7 @@ impl JobProcessor for TeeVerifierInputProducer { .context("failed to mark job as successful for TeeVerifierInputProducer")?; transaction .tee_proof_generation_dal() - .insert_tee_proof_generation_job(job_id) + .insert_tee_proof_generation_job(job_id, TeeType::Sgx) .await?; transaction .commit()