From f119308d7ee1b75314baeb89c289d7a5df830a7d Mon Sep 17 00:00:00 2001 From: Juan Munoz Date: Thu, 30 Jan 2025 16:00:19 -0300 Subject: [PATCH] merge latest p2 --- core/Cargo.lock | 29 +- core/Cargo.toml | 2 +- core/node/da_clients/src/eigen/client.rs | 48 +- core/node/da_clients/src/eigen/errors.rs | 111 --- .../node/da_clients/src/eigen/verifier/mod.rs | 545 ------------ .../da_clients/src/eigen/verifier/tests.rs | 795 ------------------ .../layers/da_clients/eigen.rs | 52 +- 7 files changed, 57 insertions(+), 1525 deletions(-) delete mode 100644 core/node/da_clients/src/eigen/errors.rs delete mode 100644 core/node/da_clients/src/eigen/verifier/mod.rs delete mode 100644 core/node/da_clients/src/eigen/verifier/tests.rs diff --git a/core/Cargo.lock b/core/Cargo.lock index 228365f40521..40e47ae1e588 100644 --- a/core/Cargo.lock +++ b/core/Cargo.lock @@ -158,7 +158,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74e60b084fe1aef8acecda2743ff2d93c18ff3eb67a2d3b12f62582a1e66ef5e" dependencies = [ "serde", - "winnow 0.6.25", + "winnow 0.6.26", ] [[package]] @@ -2845,7 +2845,7 @@ dependencies = [ [[package]] name = "eigen-client" version = "0.1.0" -source = "git+https://github.com/lambdaclass/eigenda-client-rs?branch=client-implementation#3703873d106f7e5377a15402b2ac397091085e73" +source = "git+https://github.com/lambdaclass/eigenda-client-rs?branch=m0-implementation#1f722784f7282b4ff0791ad98c19a3a8e7149363" dependencies = [ "ark-bn254", "async-trait", @@ -2866,6 +2866,7 @@ dependencies = [ "serde_json", "sha3 0.10.8", "subxt-signer", + "tempfile", "thiserror 1.0.69", "tiny-keccak 2.0.2", "tokio", @@ -2925,9 +2926,9 @@ dependencies = [ [[package]] name = "elsa" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98e71ae4df57d214182a2e5cb90230c0192c6ddfcaa05c36453d46a54713e10" +checksum = "2343daaeabe09879d4ea058bb4f1e63da3fc07dadc6634e01bda1b3d6a9d9d2b" dependencies = [ "stable_deref_trait", ] @@ -3355,7 +3356,7 @@ dependencies = [ "tokio", "tracing", "walkdir", - "winnow 0.6.25", + "winnow 0.6.26", "yansi", ] @@ -6315,30 +6316,28 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.7.2" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91c2d9a6a6004e205b7e881856fb1a0f5022d382acc2c01b52185f7b6f65997" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ "arrayvec 0.7.6", "bitvec", "byte-slice-cast", - "const_format", "impl-trait-for-tuples", "parity-scale-codec-derive", - "rustversion", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "3.7.2" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77555fd9d578b6470470463fded832619a5fec5ad6cbc551fe4d7507ce50cd3a" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2 1.0.93", "quote 1.0.38", - "syn 2.0.96", + "syn 1.0.109", ] [[package]] @@ -10178,7 +10177,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.25", + "winnow 0.6.26", ] [[package]] @@ -11223,9 +11222,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.25" +version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad699df48212c6cc6eb4435f35500ac6fd3b9913324f938aea302022ce19d310" +checksum = "1e90edd2ac1aa278a5c4599b1d89cf03074b610800f866d4026dc199d7929a28" dependencies = [ "memchr", ] diff --git a/core/Cargo.toml b/core/Cargo.toml index dd5425a6e725..47341984595d 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -222,7 +222,7 @@ tonic = { version = "0.11.0", default-features = false } pbjson-types = "0.6.0" # Eigen -eigenda-client-rs = {git = "https://github.com/lambdaclass/eigenda-client-rs", branch = "client-implementation", package = "eigen-client"} +eigenda-client-rs = {git = "https://github.com/lambdaclass/eigenda-client-rs", branch = "m0-implementation", package = "eigen-client"} tokio-stream = "0.1.16" rust-kzg-bn254 = "0.2.1" ark-bn254 = "0.5.0" diff --git a/core/node/da_clients/src/eigen/client.rs b/core/node/da_clients/src/eigen/client.rs index c84cbb1f10af..49adfd41cea8 100644 --- a/core/node/da_clients/src/eigen/client.rs +++ b/core/node/da_clients/src/eigen/client.rs @@ -1,13 +1,13 @@ -use std::{error::Error, str::FromStr}; +use std::{str::FromStr, sync::Arc}; use eigenda_client_rs::{client::GetBlobData, EigenClient}; use subxt_signer::ExposeSecret; +use url::Url; use zksync_config::{configs::da_client::eigen::EigenSecrets, EigenConfig}; use zksync_da_client::{ types::{DAError, DispatchResponse, InclusionData}, DataAvailabilityClient, }; -use zksync_dal::{ConnectionPool, Core, CoreDal}; use crate::utils::to_retriable_da_error; @@ -16,20 +16,29 @@ use crate::utils::to_retriable_da_error; pub struct EigenDAClient { client: EigenClient, } + impl EigenDAClient { pub async fn new( config: EigenConfig, secrets: EigenSecrets, - pool: ConnectionPool, - // get_blob_data: Box, // TODO: repalce `pool` above for this + get_blob_data: Arc, ) -> anyhow::Result { + let eigenda_eth_rpc = match config.eigenda_eth_rpc { + Some(url) => { + let url = Url::from_str(url.expose_str()) + .map_err(|_| anyhow::anyhow!("Invalid eth rpc url"))?; + Some(eigenda_client_rs::config::SecretUrl::new(url)) + } + None => None, + }; let eigen_config = eigenda_client_rs::config::EigenConfig { disperser_rpc: config.disperser_rpc, settlement_layer_confirmation_depth: config.settlement_layer_confirmation_depth, - eigenda_eth_rpc: "TODO: FIX".to_string(), - eigenda_svc_manager_address: "TODO: FIX".to_string(), // config.eigenda_svc_manager_address, + eigenda_eth_rpc, + eigenda_svc_manager_address: config.eigenda_svc_manager_address, wait_for_finalization: config.wait_for_finalization, authenticated: config.authenticated, + points_dir: config.points_dir, g1_url: config.g1_url, g2_url: config.g2_url, }; @@ -37,38 +46,13 @@ impl EigenDAClient { eigenda_client_rs::config::PrivateKey::from_str(secrets.private_key.0.expose_secret()) .map_err(|_| anyhow::anyhow!("Invalid private key"))?; let eigen_secrets = eigenda_client_rs::config::EigenSecrets { private_key }; - let get_blob_data = GetBlobFromDB { pool }; - let client = EigenClient::new(eigen_config, eigen_secrets, Box::new(get_blob_data)) + let client = EigenClient::new(eigen_config, eigen_secrets, get_blob_data) .await .map_err(|e| anyhow::anyhow!("Eigen client Error: {:?}", e))?; Ok(Self { client }) } } -#[derive(Debug, Clone)] -pub struct GetBlobFromDB { - pool: ConnectionPool, -} - -#[async_trait::async_trait] -impl GetBlobData for GetBlobFromDB { - async fn get_blob_data( - &self, - input: &str, - ) -> Result>, Box> { - let mut conn = self.pool.connection_tagged("eigen_client").await?; - let batch = conn - .data_availability_dal() - .get_blob_data_by_blob_id(input) - .await?; - Ok(batch.map(|b| b.pubdata)) - } - - fn clone_boxed(&self) -> Box { - Box::new(self.clone()) - } -} - #[async_trait::async_trait] impl DataAvailabilityClient for EigenDAClient { async fn dispatch_blob( diff --git a/core/node/da_clients/src/eigen/errors.rs b/core/node/da_clients/src/eigen/errors.rs deleted file mode 100644 index b2eba8ee843e..000000000000 --- a/core/node/da_clients/src/eigen/errors.rs +++ /dev/null @@ -1,111 +0,0 @@ -use ark_bn254::G1Affine; -use tonic::{transport::Error as TonicError, Status}; -use zksync_eth_client::EnrichedClientError; - -use super::blob_info::BlobQuorumParam; - -/// Errors returned by this crate -#[derive(Debug, thiserror::Error)] -pub enum EigenClientError { - #[error(transparent)] - EthClient(#[from] EthClientError), - #[error(transparent)] - Verification(#[from] VerificationError), - #[error(transparent)] - Communication(#[from] CommunicationError), - #[error(transparent)] - BlobStatus(#[from] BlobStatusError), - #[error(transparent)] - Conversion(#[from] ConversionError), - #[error(transparent)] - Config(#[from] ConfigError), -} - -#[derive(Debug, thiserror::Error)] -pub enum ConfigError { - #[error(transparent)] - Secp(#[from] secp256k1::Error), - #[error(transparent)] - Tonic(#[from] TonicError), -} - -#[derive(Debug, thiserror::Error)] -pub enum CommunicationError { - #[error(transparent)] - Secp(#[from] secp256k1::Error), - #[error(transparent)] - Hex(#[from] hex::FromHexError), - #[error(transparent)] - GetBlobData(#[from] Box), -} - -#[derive(Debug, thiserror::Error)] -pub enum BlobStatusError { - #[error(transparent)] - Prost(#[from] prost::DecodeError), - #[error(transparent)] - Status(#[from] Status), -} - -/// Errors specific to conversion -#[derive(Debug, thiserror::Error)] -pub enum ConversionError {} - -/// Errors for the EthClient -#[derive(Debug, thiserror::Error)] -pub enum EthClientError { - #[error(transparent)] - HTTPClient(#[from] reqwest::Error), - #[error(transparent)] - SerdeJSON(#[from] serde_json::Error), - #[error("RPC: {0}")] - Rpc(String), -} - -#[derive(Debug, thiserror::Error)] -pub enum KzgError { - #[error("Kzg setup error: {0}")] - Setup(String), - #[error(transparent)] - Internal(#[from] rust_kzg_bn254::errors::KzgError), -} - -#[derive(Debug, thiserror::Error)] -pub enum ServiceManagerError { - #[error(transparent)] - EnrichedClient(#[from] EnrichedClientError), - #[error("Decoding error: {0}")] - Decoding(String), -} - -/// Errors for the Verifier -#[derive(Debug, thiserror::Error)] -pub enum VerificationError { - #[error(transparent)] - ServiceManager(#[from] ServiceManagerError), - #[error(transparent)] - Kzg(#[from] KzgError), - #[error("Wrong proof")] - WrongProof, - #[error("Different commitments: expected {expected:?}, got {actual:?}")] - DifferentCommitments { - expected: Box, - actual: Box, - }, - #[error("Different roots: expected {expected:?}, got {actual:?}")] - DifferentRoots { expected: String, actual: String }, - #[error("Empty hashes")] - EmptyHash, - #[error("Different hashes: expected {expected:?}, got {actual:?}")] - DifferentHashes { expected: String, actual: String }, - #[error("Wrong quorum params: {blob_quorum_params:?}")] - WrongQuorumParams { blob_quorum_params: BlobQuorumParam }, - #[error("Quorum not confirmed")] - QuorumNotConfirmed, - #[error("Commitment not on curve: {0}")] - CommitmentNotOnCurve(G1Affine), - #[error("Commitment not on correct subgroup: {0}")] - CommitmentNotOnCorrectSubgroup(G1Affine), - #[error("Point download error: {0}")] - PointDownloadError(String), -} diff --git a/core/node/da_clients/src/eigen/verifier/mod.rs b/core/node/da_clients/src/eigen/verifier/mod.rs deleted file mode 100644 index 295b474bda3d..000000000000 --- a/core/node/da_clients/src/eigen/verifier/mod.rs +++ /dev/null @@ -1,545 +0,0 @@ -use std::{ - collections::HashMap, - io::Write, - path::{Path, PathBuf}, - sync::Arc, -}; - -use ark_bn254::{Fq, G1Affine}; -use ethabi::{encode, ParamType, Token}; -use rust_kzg_bn254::{blob::Blob, kzg::Kzg, polynomial::PolynomialFormat}; -use tempfile::NamedTempFile; -use tokio::task::JoinHandle; -use zksync_basic_types::web3::CallRequest; -use zksync_config::EigenConfig; -use zksync_eth_client::EthInterface; -use zksync_types::{web3, Address, U256, U64}; -use zksync_web3_decl::client::{DynClient, L1}; - -use super::{ - blob_info::{BatchHeader, BlobHeader, BlobInfo, G1Commitment}, - errors::{KzgError, ServiceManagerError, VerificationError}, - sdk::RawEigenClient, -}; - -#[cfg(test)] -mod tests; - -fn decode_bytes(encoded: Vec) -> Result, VerificationError> { - let output_type = [ParamType::Bytes]; - let tokens = ethabi::decode(&output_type, &encoded) - .map_err(|e| ServiceManagerError::Decoding(e.to_string()))?; - - // Safe unwrap because decode guarantees type correctness and non-empty output - let token = tokens.into_iter().next().unwrap(); - - // Safe unwrap, as type is guaranteed - Ok(token.into_bytes().unwrap()) -} - -#[async_trait::async_trait] -pub trait VerifierClient: Sync + Send + std::fmt::Debug { - /// Request to the EigenDA service manager contract - /// the batch metadata hash for a given batch id - async fn batch_id_to_batch_metadata_hash( - &self, - batch_id: u32, - svc_manager_addr: Address, - settlement_layer_confirmation_depth: Option, - ) -> Result, VerificationError>; - - /// Request to the EigenDA service manager contract - /// the quorum adversary threshold percentages for a given quorum number - async fn quorum_adversary_threshold_percentages( - &self, - quorum_number: u32, - svc_manager_addr: Address, - ) -> Result; - - /// Request to the EigenDA service manager contract - /// the set of quorum numbers that are required - async fn required_quorum_numbers( - &self, - svc_manager_addr: Address, - ) -> Result, VerificationError>; -} - -#[async_trait::async_trait] -impl VerifierClient for Box> { - async fn batch_id_to_batch_metadata_hash( - &self, - batch_id: u32, - svc_manager_addr: Address, - settlement_layer_confirmation_depth: Option, - ) -> Result, VerificationError> { - let mut data = vec![]; - let func_selector = - ethabi::short_signature("batchIdToBatchMetadataHash", &[ParamType::Uint(32)]); - data.extend_from_slice(&func_selector); - let batch_id_data = encode(&[Token::Uint(U256::from(batch_id))]); - data.extend_from_slice(&batch_id_data); - - let call_request = CallRequest { - to: Some(svc_manager_addr), - data: Some(zksync_basic_types::web3::Bytes(data)), - ..Default::default() - }; - - let block_id = match settlement_layer_confirmation_depth { - Some(depth) => { - let depth = depth.saturating_sub(U64::one()); - let mut current_block = self - .block_number() - .await - .map_err(ServiceManagerError::EnrichedClient)?; - current_block = current_block.saturating_sub(depth); - Some(current_block.into()) - } - None => None, - }; - - let res = self - .as_ref() - .call_contract_function(call_request, block_id) - .await - .map_err(ServiceManagerError::EnrichedClient)?; - - Ok(res.0.to_vec()) - } - - async fn quorum_adversary_threshold_percentages( - &self, - quorum_number: u32, - svc_manager_addr: Address, - ) -> Result { - let func_selector = ethabi::short_signature("quorumAdversaryThresholdPercentages", &[]); - let data = func_selector.to_vec(); - - let call_request = CallRequest { - to: Some(svc_manager_addr), - data: Some(zksync_basic_types::web3::Bytes(data)), - ..Default::default() - }; - - let res = self - .as_ref() - .call_contract_function(call_request, None) - .await - .map_err(ServiceManagerError::EnrichedClient)?; - - let percentages = decode_bytes(res.0)?; - - if percentages.len() > quorum_number as usize { - return Ok(percentages[quorum_number as usize]); - } - Ok(0) - } - - async fn required_quorum_numbers( - &self, - svc_manager_addr: Address, - ) -> Result, VerificationError> { - let func_selector = ethabi::short_signature("quorumNumbersRequired", &[]); - let data = func_selector.to_vec(); - let call_request = CallRequest { - to: Some(svc_manager_addr), - data: Some(zksync_basic_types::web3::Bytes(data)), - ..Default::default() - }; - let res = self - .as_ref() - .call_contract_function(call_request, None) - .await - .map_err(ServiceManagerError::EnrichedClient)?; - - decode_bytes(res.0.to_vec()) - } -} - -#[derive(Debug)] -enum PointFile { - Temp(NamedTempFile), - Path(PathBuf), -} - -impl PointFile { - fn path(&self) -> &Path { - match self { - PointFile::Temp(file) => file.path(), - PointFile::Path(path) => path.as_path(), - } - } -} - -/// Verifier used to verify the integrity of the blob info -/// Kzg is used for commitment verification -/// EigenDA service manager is used to connect to the service manager contract -#[derive(Debug)] -pub struct Verifier { - kzg: Kzg, - cfg: EigenConfig, - client: Arc, -} - -impl Verifier { - pub const DEFAULT_PRIORITY_FEE_PER_GAS: u64 = 100; - pub const SRSORDER: u32 = 1 << 28; // 2 ^ 28 - pub const G1POINT: &'static str = "g1.point"; - pub const G2POINT: &'static str = "g2.point.powerOf2"; - pub const POINT_SIZE: u32 = 32; - - async fn download_temp_point(url: &String) -> Result { - let response = reqwest::get(url) - .await - .map_err(|e| VerificationError::PointDownloadError(e.to_string()))?; - - if !response.status().is_success() { - return Err(VerificationError::PointDownloadError(format!( - "Failed to download point from source {}", - url - ))); - } - - let content = response - .bytes() - .await - .map_err(|e| VerificationError::PointDownloadError(e.to_string()))?; - - // Tempfile writting uses `std::fs`, so we need to spawn a blocking task - let temp_file = tokio::task::spawn_blocking(move || { - let mut file = NamedTempFile::new() - .map_err(|e| VerificationError::PointDownloadError(e.to_string()))?; - - file.write_all(&content) - .map_err(|e| VerificationError::PointDownloadError(e.to_string()))?; - - file.flush() - .map_err(|e| VerificationError::PointDownloadError(e.to_string()))?; - - Ok::(file) - }) - .await - .map_err(|e| VerificationError::PointDownloadError(e.to_string()))??; - - Ok::(temp_file) - } - - async fn get_points(cfg: &EigenConfig) -> Result<(PointFile, PointFile), VerificationError> { - match &cfg.points_dir { - Some(path) => Ok(( - PointFile::Path(PathBuf::from(format!("{}/{}", path, Self::G1POINT))), - PointFile::Path(PathBuf::from(format!("{}/{}", path, Self::G2POINT))), - )), - None => { - tracing::info!("Points for KZG setup not found, downloading points to a temp file"); - Ok(( - PointFile::Temp(Self::download_temp_point(&cfg.g1_url).await?), - PointFile::Temp(Self::download_temp_point(&cfg.g2_url).await?), - )) - } - } - } - - pub(crate) async fn new( - cfg: EigenConfig, - client: Arc, - ) -> Result { - let srs_points_to_load = RawEigenClient::blob_size_limit() as u32 / Self::POINT_SIZE; - let (g1_point_file, g2_point_file) = Self::get_points(&cfg).await?; - let kzg_handle: JoinHandle> = - tokio::task::spawn_blocking(move || { - let g1_point_file_path = g1_point_file.path().to_str().ok_or(KzgError::Setup( - "Could not format point path into a valid string".to_string(), - ))?; - let g2_point_file_path = g2_point_file.path().to_str().ok_or(KzgError::Setup( - "Could not format point path into a valid string".to_string(), - ))?; - Kzg::setup( - g1_point_file_path, - "", - g2_point_file_path, - Self::SRSORDER, - srs_points_to_load, - "".to_string(), - ) - .map_err(KzgError::Internal) - }); - let kzg = kzg_handle - .await - .map_err(|e| VerificationError::Kzg(KzgError::Setup(e.to_string())))??; - - Ok(Self { kzg, cfg, client }) - } - - /// Return the commitment from a blob - fn commit(&self, blob: &[u8]) -> Result { - let blob = Blob::from_bytes_and_pad(blob); - self.kzg - .blob_to_kzg_commitment(&blob, PolynomialFormat::InEvaluationForm) - .map_err(|e| VerificationError::Kzg(KzgError::Internal(e))) - } - - /// Compare the given commitment with the commitment generated with the blob - pub fn verify_commitment( - &self, - expected_commitment: G1Commitment, - blob: &[u8], - ) -> Result<(), VerificationError> { - let actual_commitment = self.commit(blob)?; - let expected_commitment = G1Affine::new_unchecked( - Fq::from(num_bigint::BigUint::from_bytes_be(&expected_commitment.x)), - Fq::from(num_bigint::BigUint::from_bytes_be(&expected_commitment.y)), - ); - if !expected_commitment.is_on_curve() { - return Err(VerificationError::CommitmentNotOnCurve(expected_commitment)); - } - if !expected_commitment.is_in_correct_subgroup_assuming_on_curve() { - return Err(VerificationError::CommitmentNotOnCorrectSubgroup( - expected_commitment, - )); - } - if actual_commitment != expected_commitment { - return Err(VerificationError::DifferentCommitments { - expected: Box::new(expected_commitment), - actual: Box::new(actual_commitment), - }); - } - Ok(()) - } - - pub(crate) fn hash_encode_blob_header(&self, blob_header: &BlobHeader) -> Vec { - let mut blob_quorums = vec![]; - for quorum in &blob_header.blob_quorum_params { - let quorum = Token::Tuple(vec![ - Token::Uint(ethabi::Uint::from(quorum.quorum_number)), - Token::Uint(ethabi::Uint::from(quorum.adversary_threshold_percentage)), - Token::Uint(ethabi::Uint::from(quorum.confirmation_threshold_percentage)), - Token::Uint(ethabi::Uint::from(quorum.chunk_length)), - ]); - blob_quorums.push(quorum); - } - let blob_header = Token::Tuple(vec![ - Token::Tuple(vec![ - Token::Uint(ethabi::Uint::from_big_endian(&blob_header.commitment.x)), - Token::Uint(ethabi::Uint::from_big_endian(&blob_header.commitment.y)), - ]), - Token::Uint(ethabi::Uint::from(blob_header.data_length)), - Token::Array(blob_quorums), - ]); - - let encoded = encode(&[blob_header]); - web3::keccak256(&encoded).to_vec() - } - - pub(crate) fn process_inclusion_proof( - &self, - proof: &[u8], - leaf: [u8; 32], - index: u32, - ) -> Result, VerificationError> { - let mut index = index; - if proof.is_empty() || proof.len() % 32 != 0 { - return Err(VerificationError::WrongProof); - } - let mut computed_hash = leaf.to_vec(); - for chunk in proof.chunks(32) { - let mut buffer = [0u8; 64]; - if index % 2 == 0 { - buffer[..32].copy_from_slice(&computed_hash); - buffer[32..].copy_from_slice(chunk); - } else { - buffer[..32].copy_from_slice(chunk); - buffer[32..].copy_from_slice(&computed_hash); - } - computed_hash = web3::keccak256(&buffer).to_vec(); - index /= 2; - } - - Ok(computed_hash) - } - - /// Verifies the certificate's batch root - pub(crate) fn verify_merkle_proof(&self, cert: &BlobInfo) -> Result<(), VerificationError> { - let inclusion_proof = &cert.blob_verification_proof.inclusion_proof; - let root = &cert - .blob_verification_proof - .batch_medatada - .batch_header - .batch_root; - let blob_index = cert.blob_verification_proof.blob_index; - let blob_header = &cert.blob_header; - - let blob_header_hash = self.hash_encode_blob_header(blob_header); - let leaf_hash = web3::keccak256(&blob_header_hash); - - let generated_root = - self.process_inclusion_proof(inclusion_proof, leaf_hash, blob_index)?; - - if generated_root != *root { - return Err(VerificationError::DifferentRoots { - expected: hex::encode(root), - actual: hex::encode(&generated_root), - }); - } - Ok(()) - } - - fn hash_batch_metadata( - &self, - batch_header: &BatchHeader, - signatory_record_hash: &[u8], - confirmation_block_number: u32, - ) -> Vec { - let batch_header_token = Token::Tuple(vec![ - Token::FixedBytes(batch_header.batch_root.clone()), // Clone only where necessary - Token::Bytes(batch_header.quorum_numbers.clone()), - Token::Bytes(batch_header.quorum_signed_percentages.clone()), - Token::Uint(ethabi::Uint::from(batch_header.reference_block_number)), - ]); - - let encoded = encode(&[batch_header_token]); - let header_hash = web3::keccak256(&encoded).to_vec(); - - let hash_token = Token::Tuple(vec![ - Token::FixedBytes(header_hash.to_vec()), - Token::FixedBytes(signatory_record_hash.to_owned()), // Clone only if required - ]); - - let mut hash_encoded = encode(&[hash_token]); - - hash_encoded.append(&mut confirmation_block_number.to_be_bytes().to_vec()); - web3::keccak256(&hash_encoded).to_vec() - } - - async fn call_batch_id_to_metadata_hash( - &self, - blob_info: &BlobInfo, - ) -> Result, VerificationError> { - self.client - .as_ref() - .batch_id_to_batch_metadata_hash( - blob_info.blob_verification_proof.batch_id, - self.cfg.eigenda_svc_manager_address, - Some(U64::from(self.cfg.settlement_layer_confirmation_depth)), - ) - .await - } - - /// Verifies the certificate batch hash - pub(crate) async fn verify_batch(&self, blob_info: &BlobInfo) -> Result<(), VerificationError> { - let expected_hash = self.call_batch_id_to_metadata_hash(blob_info).await?; - - if expected_hash == vec![0u8; 32] { - return Err(VerificationError::EmptyHash); - } - - let actual_hash = self.hash_batch_metadata( - &blob_info - .blob_verification_proof - .batch_medatada - .batch_header, - &blob_info - .blob_verification_proof - .batch_medatada - .signatory_record_hash, - blob_info - .blob_verification_proof - .batch_medatada - .confirmation_block_number, - ); - - if expected_hash != actual_hash { - return Err(VerificationError::DifferentHashes { - expected: hex::encode(&expected_hash), - actual: hex::encode(&actual_hash), - }); - } - Ok(()) - } - - async fn get_quorum_adversary_threshold( - &self, - quorum_number: u32, - ) -> Result { - self.client - .as_ref() - .quorum_adversary_threshold_percentages( - quorum_number, - self.cfg.eigenda_svc_manager_address, - ) - .await - } - - async fn call_quorum_numbers_required(&self) -> Result, VerificationError> { - self.client - .as_ref() - .required_quorum_numbers(self.cfg.eigenda_svc_manager_address) - .await - } - - /// Verifies that the certificate's blob quorum params are correct - pub async fn verify_security_params(&self, cert: &BlobInfo) -> Result<(), VerificationError> { - let blob_header = &cert.blob_header; - let batch_header = &cert.blob_verification_proof.batch_medatada.batch_header; - - let mut confirmed_quorums: HashMap = HashMap::new(); - for i in 0..blob_header.blob_quorum_params.len() { - if batch_header.quorum_numbers[i] as u32 - != blob_header.blob_quorum_params[i].quorum_number - { - return Err(VerificationError::WrongQuorumParams { - blob_quorum_params: blob_header.blob_quorum_params[i].clone(), - }); - } - if blob_header.blob_quorum_params[i].adversary_threshold_percentage - > blob_header.blob_quorum_params[i].confirmation_threshold_percentage - { - return Err(VerificationError::WrongQuorumParams { - blob_quorum_params: blob_header.blob_quorum_params[i].clone(), - }); - } - let quorum_adversary_threshold = self - .get_quorum_adversary_threshold(blob_header.blob_quorum_params[i].quorum_number) - .await?; - - if quorum_adversary_threshold > 0 - && blob_header.blob_quorum_params[i].adversary_threshold_percentage - < quorum_adversary_threshold as u32 - { - return Err(VerificationError::WrongQuorumParams { - blob_quorum_params: blob_header.blob_quorum_params[i].clone(), - }); - } - - if (batch_header.quorum_signed_percentages[i] as u32) - < blob_header.blob_quorum_params[i].confirmation_threshold_percentage - { - return Err(VerificationError::WrongQuorumParams { - blob_quorum_params: blob_header.blob_quorum_params[i].clone(), - }); - } - - confirmed_quorums.insert(blob_header.blob_quorum_params[i].quorum_number, true); - } - - let required_quorums = self.call_quorum_numbers_required().await?; - - for quorum in required_quorums { - if !confirmed_quorums.contains_key(&(quorum as u32)) { - return Err(VerificationError::QuorumNotConfirmed); - } - } - Ok(()) - } - - /// Verifies that the certificate is valid - pub async fn verify_inclusion_data_against_settlement_layer( - &self, - cert: &BlobInfo, - ) -> Result<(), VerificationError> { - self.verify_batch(cert).await?; - self.verify_merkle_proof(cert)?; - self.verify_security_params(cert).await?; - Ok(()) - } -} diff --git a/core/node/da_clients/src/eigen/verifier/tests.rs b/core/node/da_clients/src/eigen/verifier/tests.rs deleted file mode 100644 index 034723fcc37b..000000000000 --- a/core/node/da_clients/src/eigen/verifier/tests.rs +++ /dev/null @@ -1,795 +0,0 @@ -use std::{collections::HashMap, str::FromStr, sync::Arc}; - -use ethabi::{ParamType, Token}; -use zksync_config::EigenConfig; -use zksync_types::{ - url::SensitiveUrl, - web3::{Bytes, CallRequest}, - Address, H160, U256, U64, -}; -use zksync_web3_decl::client::{Client, DynClient, L1}; - -use super::VerificationError; -use crate::eigen::{ - blob_info::{ - BatchHeader, BatchMetadata, BlobHeader, BlobInfo, BlobQuorumParam, BlobVerificationProof, - G1Commitment, - }, - verifier::{decode_bytes, Verifier, VerifierClient}, -}; - -/// Mock struct for the Verifier -/// Used to avoid making actual calls to a remote disperser -/// and possible making the CI fail due to network issues. -/// To run tests with the actual verifier run: -/// `cargo test -p zksync_da_clients -- --ignored` -#[derive(Debug)] -pub struct MockVerifierClient { - replies: HashMap, -} - -impl MockVerifierClient { - pub fn new(replies: HashMap) -> Self { - Self { replies } - } -} - -#[async_trait::async_trait] -impl VerifierClient for MockVerifierClient { - async fn batch_id_to_batch_metadata_hash( - &self, - batch_id: u32, - svc_manager_addr: Address, - _settlement_layer_confirmation_depth: Option, - ) -> Result, VerificationError> { - let mut data = vec![]; - let func_selector = - ethabi::short_signature("batchIdToBatchMetadataHash", &[ParamType::Uint(32)]); - data.extend_from_slice(&func_selector); - let batch_id_data = ethabi::encode(&[Token::Uint(U256::from(batch_id))]); - data.extend_from_slice(&batch_id_data); - - let call_request = CallRequest { - to: Some(svc_manager_addr), - data: Some(zksync_basic_types::web3::Bytes(data)), - ..Default::default() - }; - - let req = serde_json::to_string(&call_request).unwrap(); - Ok(self.replies.get(&req).unwrap().clone().0) - } - - async fn quorum_adversary_threshold_percentages( - &self, - quorum_number: u32, - svc_manager_addr: Address, - ) -> Result { - let func_selector = ethabi::short_signature("quorumAdversaryThresholdPercentages", &[]); - let data = func_selector.to_vec(); - - let call_request = CallRequest { - to: Some(svc_manager_addr), - data: Some(zksync_basic_types::web3::Bytes(data)), - ..Default::default() - }; - - let req = serde_json::to_string(&call_request).unwrap(); - let res = self.replies.get(&req).unwrap().clone(); - let percentages = decode_bytes(res.0)?; - - if percentages.len() > quorum_number as usize { - return Ok(percentages[quorum_number as usize]); - } - Ok(0) - } - - async fn required_quorum_numbers( - &self, - svc_manager_addr: Address, - ) -> Result, VerificationError> { - let func_selector = ethabi::short_signature("quorumNumbersRequired", &[]); - let data = func_selector.to_vec(); - let call_request = CallRequest { - to: Some(svc_manager_addr), - data: Some(zksync_basic_types::web3::Bytes(data)), - ..Default::default() - }; - - let req = serde_json::to_string(&call_request).unwrap(); - let res = self.replies.get(&req).unwrap().clone(); - decode_bytes(res.0.to_vec()) - } -} - -fn create_remote_query_client() -> Box> { - let url = SensitiveUrl::from_str("https://ethereum-holesky-rpc.publicnode.com").unwrap(); - let query_client: Client = Client::http(url).unwrap().build(); - Box::new(query_client) as Box> -} - -#[ignore = "depends on external RPC"] -#[tokio::test] -async fn test_verify_commitment() { - let cfg = EigenConfig::default(); - let query_client = create_remote_query_client(); - let verifier = Verifier::new(cfg, Arc::new(query_client)).await.unwrap(); - let commitment = G1Commitment { - x: vec![ - 22, 11, 176, 29, 82, 48, 62, 49, 51, 119, 94, 17, 156, 142, 248, 96, 240, 183, 134, 85, - 152, 5, 74, 27, 175, 83, 162, 148, 17, 110, 201, 74, - ], - y: vec![ - 12, 132, 236, 56, 147, 6, 176, 135, 244, 166, 21, 18, 87, 76, 122, 3, 23, 22, 254, 236, - 148, 129, 110, 207, 131, 116, 58, 170, 4, 130, 191, 157, - ], - }; - let blob = vec![1u8; 100]; // Actual blob sent was this blob but kzg-padded, but Blob::from_bytes_and_pad padds it inside, so we don't need to pad it here. - let result = verifier.verify_commitment(commitment, &blob); - assert!(result.is_ok()); -} - -/// Test the verification of the commitment with a mocked verifier. -/// To test actual behaviour of the verifier, run the test above -#[tokio::test] -async fn test_verify_commitment_mocked() { - let cfg = EigenConfig::default(); - let query_client = MockVerifierClient::new(HashMap::new()); - let verifier = Verifier::new(cfg, Arc::new(query_client)).await.unwrap(); - let commitment = G1Commitment { - x: vec![ - 22, 11, 176, 29, 82, 48, 62, 49, 51, 119, 94, 17, 156, 142, 248, 96, 240, 183, 134, 85, - 152, 5, 74, 27, 175, 83, 162, 148, 17, 110, 201, 74, - ], - y: vec![ - 12, 132, 236, 56, 147, 6, 176, 135, 244, 166, 21, 18, 87, 76, 122, 3, 23, 22, 254, 236, - 148, 129, 110, 207, 131, 116, 58, 170, 4, 130, 191, 157, - ], - }; - let blob = vec![1u8; 100]; // Actual blob sent was this blob but kzg-padded, but Blob::from_bytes_and_pad padds it inside, so we don't need to pad it here. - let result = verifier.verify_commitment(commitment, &blob); - assert!(result.is_ok()); -} - -#[ignore = "depends on external RPC"] -#[tokio::test] -async fn test_verify_merkle_proof() { - let cfg = EigenConfig::default(); - let query_client = create_remote_query_client(); - let verifier = Verifier::new(cfg, Arc::new(query_client)).await.unwrap(); - let cert = BlobInfo { - blob_header: BlobHeader { - commitment: G1Commitment { - x: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - ], - y: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - ], - }, - data_length: 4, - blob_quorum_params: vec![ - BlobQuorumParam { - quorum_number: 0, - adversary_threshold_percentage: 33, - confirmation_threshold_percentage: 55, - chunk_length: 1, - }, - BlobQuorumParam { - quorum_number: 1, - adversary_threshold_percentage: 33, - confirmation_threshold_percentage: 55, - chunk_length: 1, - }, - ], - }, - blob_verification_proof: BlobVerificationProof { - batch_id: 66507, - blob_index: 92, - batch_medatada: BatchMetadata { - batch_header: BatchHeader { - batch_root: vec![ - 179, 187, 53, 98, 192, 80, 151, 28, 125, 192, 115, 29, 129, 238, 216, 8, - 213, 210, 203, 143, 181, 19, 146, 113, 98, 131, 39, 238, 149, 248, 211, 43, - ], - quorum_numbers: vec![0, 1], - quorum_signed_percentages: vec![100, 100], - reference_block_number: 2624794, - }, - signatory_record_hash: vec![ - 172, 32, 172, 142, 197, 52, 84, 143, 120, 26, 190, 9, 143, 217, 62, 19, 17, - 107, 105, 67, 203, 5, 172, 249, 6, 60, 105, 240, 134, 34, 66, 133, - ], - fee: vec![0], - confirmation_block_number: 2624876, - batch_header_hash: vec![ - 122, 115, 2, 85, 233, 75, 121, 85, 51, 81, 248, 170, 198, 252, 42, 16, 1, 146, - 96, 218, 159, 44, 41, 40, 94, 247, 147, 11, 255, 68, 40, 177, - ], - }, - inclusion_proof: vec![ - 203, 160, 237, 48, 117, 255, 75, 254, 117, 144, 164, 77, 29, 146, 36, 48, 190, 140, - 50, 100, 144, 237, 125, 125, 75, 54, 210, 247, 147, 23, 48, 189, 120, 4, 125, 123, - 195, 244, 207, 239, 145, 109, 0, 21, 11, 162, 109, 79, 192, 100, 138, 157, 203, 22, - 17, 114, 234, 72, 174, 231, 209, 133, 99, 118, 201, 160, 137, 128, 112, 84, 34, - 136, 174, 139, 96, 26, 246, 148, 134, 52, 200, 229, 160, 145, 5, 120, 18, 187, 51, - 11, 109, 91, 237, 171, 215, 207, 90, 95, 146, 54, 135, 166, 66, 157, 255, 237, 69, - 183, 141, 45, 162, 145, 71, 16, 87, 184, 120, 84, 156, 220, 159, 4, 99, 48, 191, - 203, 136, 112, 127, 226, 192, 184, 110, 6, 177, 182, 109, 207, 197, 239, 161, 132, - 17, 89, 56, 137, 205, 202, 101, 97, 60, 162, 253, 23, 169, 75, 236, 211, 126, 121, - 132, 191, 68, 167, 200, 16, 154, 149, 202, 197, 7, 191, 26, 8, 67, 3, 37, 137, 16, - 153, 30, 209, 238, 53, 233, 148, 198, 253, 94, 216, 73, 25, 190, 205, 132, 208, - 255, 219, 170, 98, 17, 160, 179, 183, 200, 17, 99, 36, 130, 216, 223, 72, 222, 250, - 73, 78, 79, 72, 253, 105, 245, 84, 244, 196, - ], - quorum_indexes: vec![0, 1], - }, - }; - let result = verifier.verify_merkle_proof(&cert); - assert!(result.is_ok()); -} - -/// Test the verificarion of a merkle proof with a mocked verifier. -/// To test actual behaviour of the verifier, run the test above -#[tokio::test] -async fn test_verify_merkle_proof_mocked() { - let cfg = EigenConfig::default(); - let query_client = MockVerifierClient::new(HashMap::new()); - let verifier = Verifier::new(cfg, Arc::new(query_client)).await.unwrap(); - let cert = BlobInfo { - blob_header: BlobHeader { - commitment: G1Commitment { - x: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - ], - y: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - ], - }, - data_length: 4, - blob_quorum_params: vec![ - BlobQuorumParam { - quorum_number: 0, - adversary_threshold_percentage: 33, - confirmation_threshold_percentage: 55, - chunk_length: 1, - }, - BlobQuorumParam { - quorum_number: 1, - adversary_threshold_percentage: 33, - confirmation_threshold_percentage: 55, - chunk_length: 1, - }, - ], - }, - blob_verification_proof: BlobVerificationProof { - batch_id: 66507, - blob_index: 92, - batch_medatada: BatchMetadata { - batch_header: BatchHeader { - batch_root: vec![ - 179, 187, 53, 98, 192, 80, 151, 28, 125, 192, 115, 29, 129, 238, 216, 8, - 213, 210, 203, 143, 181, 19, 146, 113, 98, 131, 39, 238, 149, 248, 211, 43, - ], - quorum_numbers: vec![0, 1], - quorum_signed_percentages: vec![100, 100], - reference_block_number: 2624794, - }, - signatory_record_hash: vec![ - 172, 32, 172, 142, 197, 52, 84, 143, 120, 26, 190, 9, 143, 217, 62, 19, 17, - 107, 105, 67, 203, 5, 172, 249, 6, 60, 105, 240, 134, 34, 66, 133, - ], - fee: vec![0], - confirmation_block_number: 2624876, - batch_header_hash: vec![ - 122, 115, 2, 85, 233, 75, 121, 85, 51, 81, 248, 170, 198, 252, 42, 16, 1, 146, - 96, 218, 159, 44, 41, 40, 94, 247, 147, 11, 255, 68, 40, 177, - ], - }, - inclusion_proof: vec![ - 203, 160, 237, 48, 117, 255, 75, 254, 117, 144, 164, 77, 29, 146, 36, 48, 190, 140, - 50, 100, 144, 237, 125, 125, 75, 54, 210, 247, 147, 23, 48, 189, 120, 4, 125, 123, - 195, 244, 207, 239, 145, 109, 0, 21, 11, 162, 109, 79, 192, 100, 138, 157, 203, 22, - 17, 114, 234, 72, 174, 231, 209, 133, 99, 118, 201, 160, 137, 128, 112, 84, 34, - 136, 174, 139, 96, 26, 246, 148, 134, 52, 200, 229, 160, 145, 5, 120, 18, 187, 51, - 11, 109, 91, 237, 171, 215, 207, 90, 95, 146, 54, 135, 166, 66, 157, 255, 237, 69, - 183, 141, 45, 162, 145, 71, 16, 87, 184, 120, 84, 156, 220, 159, 4, 99, 48, 191, - 203, 136, 112, 127, 226, 192, 184, 110, 6, 177, 182, 109, 207, 197, 239, 161, 132, - 17, 89, 56, 137, 205, 202, 101, 97, 60, 162, 253, 23, 169, 75, 236, 211, 126, 121, - 132, 191, 68, 167, 200, 16, 154, 149, 202, 197, 7, 191, 26, 8, 67, 3, 37, 137, 16, - 153, 30, 209, 238, 53, 233, 148, 198, 253, 94, 216, 73, 25, 190, 205, 132, 208, - 255, 219, 170, 98, 17, 160, 179, 183, 200, 17, 99, 36, 130, 216, 223, 72, 222, 250, - 73, 78, 79, 72, 253, 105, 245, 84, 244, 196, - ], - quorum_indexes: vec![0, 1], - }, - }; - let result = verifier.verify_merkle_proof(&cert); - assert!(result.is_ok()); -} - -#[ignore = "depends on external RPC"] -#[tokio::test] -async fn test_hash_blob_header() { - let cfg = EigenConfig::default(); - let query_client = create_remote_query_client(); - let verifier = Verifier::new(cfg, Arc::new(query_client)).await.unwrap(); - let blob_header = BlobHeader { - commitment: G1Commitment { - x: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, - ], - y: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, - ], - }, - data_length: 2, - blob_quorum_params: vec![ - BlobQuorumParam { - quorum_number: 2, - adversary_threshold_percentage: 4, - confirmation_threshold_percentage: 5, - chunk_length: 6, - }, - BlobQuorumParam { - quorum_number: 2, - adversary_threshold_percentage: 4, - confirmation_threshold_percentage: 5, - chunk_length: 6, - }, - ], - }; - let result = verifier.hash_encode_blob_header(&blob_header); - let expected = "ba4675a31c9bf6b2f7abfdcedd34b74645cb7332b35db39bff00ae8516a67393"; - assert_eq!(result, hex::decode(expected).unwrap()); -} - -/// Test hashing of a blob header with a mocked verifier. -/// To test actual behaviour of the verifier, run the test above -#[tokio::test] -async fn test_hash_blob_header_mocked() { - let cfg = EigenConfig::default(); - let query_client = MockVerifierClient::new(HashMap::new()); - let verifier = Verifier::new(cfg, Arc::new(query_client)).await.unwrap(); - let blob_header = BlobHeader { - commitment: G1Commitment { - x: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, - ], - y: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, - ], - }, - data_length: 2, - blob_quorum_params: vec![ - BlobQuorumParam { - quorum_number: 2, - adversary_threshold_percentage: 4, - confirmation_threshold_percentage: 5, - chunk_length: 6, - }, - BlobQuorumParam { - quorum_number: 2, - adversary_threshold_percentage: 4, - confirmation_threshold_percentage: 5, - chunk_length: 6, - }, - ], - }; - let result = verifier.hash_encode_blob_header(&blob_header); - let expected = "ba4675a31c9bf6b2f7abfdcedd34b74645cb7332b35db39bff00ae8516a67393"; - assert_eq!(result, hex::decode(expected).unwrap()); -} - -#[ignore = "depends on external RPC"] -#[tokio::test] -async fn test_inclusion_proof() { - let cfg = EigenConfig::default(); - let query_client = create_remote_query_client(); - let verifier = Verifier::new(cfg, Arc::new(query_client)).await.unwrap(); - let proof = hex::decode("c455c1ea0e725d7ea3e5f29e9f48be8fc2787bb0a914d5a86710ba302c166ac4f626d76f67f1055bb960a514fb8923af2078fd84085d712655b58a19612e8cd15c3e4ac1cef57acde3438dbcf63f47c9fefe1221344c4d5c1a4943dd0d1803091ca81a270909dc0e146841441c9bd0e08e69ce6168181a3e4060ffacf3627480bec6abdd8d7bb92b49d33f180c42f49e041752aaded9c403db3a17b85e48a11e9ea9a08763f7f383dab6d25236f1b77c12b4c49c5cdbcbea32554a604e3f1d2f466851cb43fe73617b3d01e665e4c019bf930f92dea7394c25ed6a1e200d051fb0c30a2193c459f1cfef00bf1ba6656510d16725a4d1dc031cb759dbc90bab427b0f60ddc6764681924dda848824605a4f08b7f526fe6bd4572458c94e83fbf2150f2eeb28d3011ec921996dc3e69efa52d5fcf3182b20b56b5857a926aa66605808079b4d52c0c0cfe06923fa92e65eeca2c3e6126108e8c1babf5ac522f4d7").unwrap(); - let leaf: [u8; 32] = - hex::decode("f6106e6ae4631e68abe0fa898cedbe97dbae6c7efb1b088c5aa2e8b91190ff96") - .unwrap() - .try_into() - .unwrap(); - let expected_root = - hex::decode("7390b8023db8248123dcaeca57fa6c9340bef639e204f2278fc7ec3d46ad071b").unwrap(); - - let actual_root = verifier.process_inclusion_proof(&proof, leaf, 580).unwrap(); - - assert_eq!(actual_root, expected_root); -} - -/// Test proof inclusion with a mocked verifier. -/// To test actual behaviour of the verifier, run the test above -#[tokio::test] -async fn test_inclusion_proof_mocked() { - let cfg = EigenConfig::default(); - let query_client = MockVerifierClient::new(HashMap::new()); - let verifier = Verifier::new(cfg, Arc::new(query_client)).await.unwrap(); - let proof = hex::decode("c455c1ea0e725d7ea3e5f29e9f48be8fc2787bb0a914d5a86710ba302c166ac4f626d76f67f1055bb960a514fb8923af2078fd84085d712655b58a19612e8cd15c3e4ac1cef57acde3438dbcf63f47c9fefe1221344c4d5c1a4943dd0d1803091ca81a270909dc0e146841441c9bd0e08e69ce6168181a3e4060ffacf3627480bec6abdd8d7bb92b49d33f180c42f49e041752aaded9c403db3a17b85e48a11e9ea9a08763f7f383dab6d25236f1b77c12b4c49c5cdbcbea32554a604e3f1d2f466851cb43fe73617b3d01e665e4c019bf930f92dea7394c25ed6a1e200d051fb0c30a2193c459f1cfef00bf1ba6656510d16725a4d1dc031cb759dbc90bab427b0f60ddc6764681924dda848824605a4f08b7f526fe6bd4572458c94e83fbf2150f2eeb28d3011ec921996dc3e69efa52d5fcf3182b20b56b5857a926aa66605808079b4d52c0c0cfe06923fa92e65eeca2c3e6126108e8c1babf5ac522f4d7").unwrap(); - let leaf: [u8; 32] = - hex::decode("f6106e6ae4631e68abe0fa898cedbe97dbae6c7efb1b088c5aa2e8b91190ff96") - .unwrap() - .try_into() - .unwrap(); - let expected_root = - hex::decode("7390b8023db8248123dcaeca57fa6c9340bef639e204f2278fc7ec3d46ad071b").unwrap(); - - let actual_root = verifier.process_inclusion_proof(&proof, leaf, 580).unwrap(); - - assert_eq!(actual_root, expected_root); -} - -#[ignore = "depends on external RPC"] -#[tokio::test] -async fn test_verify_batch() { - let cfg = EigenConfig::default(); - let query_client = create_remote_query_client(); - let verifier = Verifier::new(cfg, Arc::new(query_client)).await.unwrap(); - let cert = BlobInfo { - blob_header: BlobHeader { - commitment: G1Commitment { - x: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - ], - y: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - ], - }, - data_length: 4, - blob_quorum_params: vec![ - BlobQuorumParam { - quorum_number: 0, - adversary_threshold_percentage: 33, - confirmation_threshold_percentage: 55, - chunk_length: 1, - }, - BlobQuorumParam { - quorum_number: 1, - adversary_threshold_percentage: 33, - confirmation_threshold_percentage: 55, - chunk_length: 1, - }, - ], - }, - blob_verification_proof: BlobVerificationProof { - batch_id: 66507, - blob_index: 92, - batch_medatada: BatchMetadata { - batch_header: BatchHeader { - batch_root: vec![ - 179, 187, 53, 98, 192, 80, 151, 28, 125, 192, 115, 29, 129, 238, 216, 8, - 213, 210, 203, 143, 181, 19, 146, 113, 98, 131, 39, 238, 149, 248, 211, 43, - ], - quorum_numbers: vec![0, 1], - quorum_signed_percentages: vec![100, 100], - reference_block_number: 2624794, - }, - signatory_record_hash: vec![ - 172, 32, 172, 142, 197, 52, 84, 143, 120, 26, 190, 9, 143, 217, 62, 19, 17, - 107, 105, 67, 203, 5, 172, 249, 6, 60, 105, 240, 134, 34, 66, 133, - ], - fee: vec![0], - confirmation_block_number: 2624876, - batch_header_hash: vec![ - 122, 115, 2, 85, 233, 75, 121, 85, 51, 81, 248, 170, 198, 252, 42, 16, 1, 146, - 96, 218, 159, 44, 41, 40, 94, 247, 147, 11, 255, 68, 40, 177, - ], - }, - inclusion_proof: vec![ - 203, 160, 237, 48, 117, 255, 75, 254, 117, 144, 164, 77, 29, 146, 36, 48, 190, 140, - 50, 100, 144, 237, 125, 125, 75, 54, 210, 247, 147, 23, 48, 189, 120, 4, 125, 123, - 195, 244, 207, 239, 145, 109, 0, 21, 11, 162, 109, 79, 192, 100, 138, 157, 203, 22, - 17, 114, 234, 72, 174, 231, 209, 133, 99, 118, 201, 160, 137, 128, 112, 84, 34, - 136, 174, 139, 96, 26, 246, 148, 134, 52, 200, 229, 160, 145, 5, 120, 18, 187, 51, - 11, 109, 91, 237, 171, 215, 207, 90, 95, 146, 54, 135, 166, 66, 157, 255, 237, 69, - 183, 141, 45, 162, 145, 71, 16, 87, 184, 120, 84, 156, 220, 159, 4, 99, 48, 191, - 203, 136, 112, 127, 226, 192, 184, 110, 6, 177, 182, 109, 207, 197, 239, 161, 132, - 17, 89, 56, 137, 205, 202, 101, 97, 60, 162, 253, 23, 169, 75, 236, 211, 126, 121, - 132, 191, 68, 167, 200, 16, 154, 149, 202, 197, 7, 191, 26, 8, 67, 3, 37, 137, 16, - 153, 30, 209, 238, 53, 233, 148, 198, 253, 94, 216, 73, 25, 190, 205, 132, 208, - 255, 219, 170, 98, 17, 160, 179, 183, 200, 17, 99, 36, 130, 216, 223, 72, 222, 250, - 73, 78, 79, 72, 253, 105, 245, 84, 244, 196, - ], - quorum_indexes: vec![0, 1], - }, - }; - let result = verifier.verify_batch(&cert).await; - assert!(result.is_ok()); -} - -/// Test batch verification with a mocked verifier. -/// To test actual behaviour of the verifier, run the test above -#[tokio::test] -async fn test_verify_batch_mocked() { - let mut mock_replies = HashMap::new(); - let mock_req = CallRequest { - to: Some(H160::from_str("0xd4a7e1bd8015057293f0d0a557088c286942e84b").unwrap()), - data: Some(Bytes::from( - hex::decode("eccbbfc900000000000000000000000000000000000000000000000000000000000103cb") - .unwrap(), - )), - ..Default::default() - }; - let mock_req = serde_json::to_string(&mock_req).unwrap(); - let mock_res = Bytes::from( - hex::decode("60933e76989e57d6fd210ae2fc3086958d708660ee6927f91963047ab1a91ba8").unwrap(), - ); - mock_replies.insert(mock_req, mock_res); - - let cfg = EigenConfig::default(); - let query_client = MockVerifierClient::new(mock_replies); - let verifier = Verifier::new(cfg, Arc::new(query_client)).await.unwrap(); - let cert = BlobInfo { - blob_header: BlobHeader { - commitment: G1Commitment { - x: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - ], - y: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - ], - }, - data_length: 4, - blob_quorum_params: vec![ - BlobQuorumParam { - quorum_number: 0, - adversary_threshold_percentage: 33, - confirmation_threshold_percentage: 55, - chunk_length: 1, - }, - BlobQuorumParam { - quorum_number: 1, - adversary_threshold_percentage: 33, - confirmation_threshold_percentage: 55, - chunk_length: 1, - }, - ], - }, - blob_verification_proof: BlobVerificationProof { - batch_id: 66507, - blob_index: 92, - batch_medatada: BatchMetadata { - batch_header: BatchHeader { - batch_root: vec![ - 179, 187, 53, 98, 192, 80, 151, 28, 125, 192, 115, 29, 129, 238, 216, 8, - 213, 210, 203, 143, 181, 19, 146, 113, 98, 131, 39, 238, 149, 248, 211, 43, - ], - quorum_numbers: vec![0, 1], - quorum_signed_percentages: vec![100, 100], - reference_block_number: 2624794, - }, - signatory_record_hash: vec![ - 172, 32, 172, 142, 197, 52, 84, 143, 120, 26, 190, 9, 143, 217, 62, 19, 17, - 107, 105, 67, 203, 5, 172, 249, 6, 60, 105, 240, 134, 34, 66, 133, - ], - fee: vec![0], - confirmation_block_number: 2624876, - batch_header_hash: vec![ - 122, 115, 2, 85, 233, 75, 121, 85, 51, 81, 248, 170, 198, 252, 42, 16, 1, 146, - 96, 218, 159, 44, 41, 40, 94, 247, 147, 11, 255, 68, 40, 177, - ], - }, - inclusion_proof: vec![ - 203, 160, 237, 48, 117, 255, 75, 254, 117, 144, 164, 77, 29, 146, 36, 48, 190, 140, - 50, 100, 144, 237, 125, 125, 75, 54, 210, 247, 147, 23, 48, 189, 120, 4, 125, 123, - 195, 244, 207, 239, 145, 109, 0, 21, 11, 162, 109, 79, 192, 100, 138, 157, 203, 22, - 17, 114, 234, 72, 174, 231, 209, 133, 99, 118, 201, 160, 137, 128, 112, 84, 34, - 136, 174, 139, 96, 26, 246, 148, 134, 52, 200, 229, 160, 145, 5, 120, 18, 187, 51, - 11, 109, 91, 237, 171, 215, 207, 90, 95, 146, 54, 135, 166, 66, 157, 255, 237, 69, - 183, 141, 45, 162, 145, 71, 16, 87, 184, 120, 84, 156, 220, 159, 4, 99, 48, 191, - 203, 136, 112, 127, 226, 192, 184, 110, 6, 177, 182, 109, 207, 197, 239, 161, 132, - 17, 89, 56, 137, 205, 202, 101, 97, 60, 162, 253, 23, 169, 75, 236, 211, 126, 121, - 132, 191, 68, 167, 200, 16, 154, 149, 202, 197, 7, 191, 26, 8, 67, 3, 37, 137, 16, - 153, 30, 209, 238, 53, 233, 148, 198, 253, 94, 216, 73, 25, 190, 205, 132, 208, - 255, 219, 170, 98, 17, 160, 179, 183, 200, 17, 99, 36, 130, 216, 223, 72, 222, 250, - 73, 78, 79, 72, 253, 105, 245, 84, 244, 196, - ], - quorum_indexes: vec![0, 1], - }, - }; - let result = verifier.verify_batch(&cert).await; - assert!(result.is_ok()); -} - -#[ignore = "depends on external RPC"] -#[tokio::test] -async fn test_verify_security_params() { - let cfg = EigenConfig::default(); - let query_client = create_remote_query_client(); - let verifier = Verifier::new(cfg, Arc::new(query_client)).await.unwrap(); - let cert = BlobInfo { - blob_header: BlobHeader { - commitment: G1Commitment { - x: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - ], - y: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - ], - }, - data_length: 4, - blob_quorum_params: vec![ - BlobQuorumParam { - quorum_number: 0, - adversary_threshold_percentage: 33, - confirmation_threshold_percentage: 55, - chunk_length: 1, - }, - BlobQuorumParam { - quorum_number: 1, - adversary_threshold_percentage: 33, - confirmation_threshold_percentage: 55, - chunk_length: 1, - }, - ], - }, - blob_verification_proof: BlobVerificationProof { - batch_id: 66507, - blob_index: 92, - batch_medatada: BatchMetadata { - batch_header: BatchHeader { - batch_root: vec![ - 179, 187, 53, 98, 192, 80, 151, 28, 125, 192, 115, 29, 129, 238, 216, 8, - 213, 210, 203, 143, 181, 19, 146, 113, 98, 131, 39, 238, 149, 248, 211, 43, - ], - quorum_numbers: vec![0, 1], - quorum_signed_percentages: vec![100, 100], - reference_block_number: 2624794, - }, - signatory_record_hash: vec![ - 172, 32, 172, 142, 197, 52, 84, 143, 120, 26, 190, 9, 143, 217, 62, 19, 17, - 107, 105, 67, 203, 5, 172, 249, 6, 60, 105, 240, 134, 34, 66, 133, - ], - fee: vec![0], - confirmation_block_number: 2624876, - batch_header_hash: vec![ - 122, 115, 2, 85, 233, 75, 121, 85, 51, 81, 248, 170, 198, 252, 42, 16, 1, 146, - 96, 218, 159, 44, 41, 40, 94, 247, 147, 11, 255, 68, 40, 177, - ], - }, - inclusion_proof: vec![ - 203, 160, 237, 48, 117, 255, 75, 254, 117, 144, 164, 77, 29, 146, 36, 48, 190, 140, - 50, 100, 144, 237, 125, 125, 75, 54, 210, 247, 147, 23, 48, 189, 120, 4, 125, 123, - 195, 244, 207, 239, 145, 109, 0, 21, 11, 162, 109, 79, 192, 100, 138, 157, 203, 22, - 17, 114, 234, 72, 174, 231, 209, 133, 99, 118, 201, 160, 137, 128, 112, 84, 34, - 136, 174, 139, 96, 26, 246, 148, 134, 52, 200, 229, 160, 145, 5, 120, 18, 187, 51, - 11, 109, 91, 237, 171, 215, 207, 90, 95, 146, 54, 135, 166, 66, 157, 255, 237, 69, - 183, 141, 45, 162, 145, 71, 16, 87, 184, 120, 84, 156, 220, 159, 4, 99, 48, 191, - 203, 136, 112, 127, 226, 192, 184, 110, 6, 177, 182, 109, 207, 197, 239, 161, 132, - 17, 89, 56, 137, 205, 202, 101, 97, 60, 162, 253, 23, 169, 75, 236, 211, 126, 121, - 132, 191, 68, 167, 200, 16, 154, 149, 202, 197, 7, 191, 26, 8, 67, 3, 37, 137, 16, - 153, 30, 209, 238, 53, 233, 148, 198, 253, 94, 216, 73, 25, 190, 205, 132, 208, - 255, 219, 170, 98, 17, 160, 179, 183, 200, 17, 99, 36, 130, 216, 223, 72, 222, 250, - 73, 78, 79, 72, 253, 105, 245, 84, 244, 196, - ], - quorum_indexes: vec![0, 1], - }, - }; - let result = verifier.verify_security_params(&cert).await; - assert!(result.is_ok()); -} - -/// Test security params verification with a mocked verifier. -/// To test actual behaviour of the verifier, run the test above -#[tokio::test] -async fn test_verify_securityt_params_mocked() { - let mut mock_replies = HashMap::new(); - - // First request - let mock_req = CallRequest { - to: Some(H160::from_str("0xd4a7e1bd8015057293f0d0a557088c286942e84b").unwrap()), - data: Some(Bytes::from(hex::decode("8687feae").unwrap())), - ..Default::default() - }; - let mock_req = serde_json::to_string(&mock_req).unwrap(); - let mock_res = Bytes::from( - hex::decode("000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000032121210000000000000000000000000000000000000000000000000000000000") - .unwrap(), - ); - mock_replies.insert(mock_req, mock_res); - - // Second request - let mock_req = CallRequest { - to: Some(H160::from_str("0xd4a7e1bd8015057293f0d0a557088c286942e84b").unwrap()), - data: Some(Bytes::from(hex::decode("e15234ff").unwrap())), - ..Default::default() - }; - let mock_req = serde_json::to_string(&mock_req).unwrap(); - let mock_res = Bytes::from( - hex::decode("000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020001000000000000000000000000000000000000000000000000000000000000") - .unwrap(), - ); - mock_replies.insert(mock_req, mock_res); - - let cfg = EigenConfig::default(); - let client = MockVerifierClient::new(mock_replies); - let verifier = Verifier::new(cfg, Arc::new(client)).await.unwrap(); - let cert = BlobInfo { - blob_header: BlobHeader { - commitment: G1Commitment { - x: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - ], - y: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - ], - }, - data_length: 4, - blob_quorum_params: vec![ - BlobQuorumParam { - quorum_number: 0, - adversary_threshold_percentage: 33, - confirmation_threshold_percentage: 55, - chunk_length: 1, - }, - BlobQuorumParam { - quorum_number: 1, - adversary_threshold_percentage: 33, - confirmation_threshold_percentage: 55, - chunk_length: 1, - }, - ], - }, - blob_verification_proof: BlobVerificationProof { - batch_id: 66507, - blob_index: 92, - batch_medatada: BatchMetadata { - batch_header: BatchHeader { - batch_root: vec![ - 179, 187, 53, 98, 192, 80, 151, 28, 125, 192, 115, 29, 129, 238, 216, 8, - 213, 210, 203, 143, 181, 19, 146, 113, 98, 131, 39, 238, 149, 248, 211, 43, - ], - quorum_numbers: vec![0, 1], - quorum_signed_percentages: vec![100, 100], - reference_block_number: 2624794, - }, - signatory_record_hash: vec![ - 172, 32, 172, 142, 197, 52, 84, 143, 120, 26, 190, 9, 143, 217, 62, 19, 17, - 107, 105, 67, 203, 5, 172, 249, 6, 60, 105, 240, 134, 34, 66, 133, - ], - fee: vec![0], - confirmation_block_number: 2624876, - batch_header_hash: vec![ - 122, 115, 2, 85, 233, 75, 121, 85, 51, 81, 248, 170, 198, 252, 42, 16, 1, 146, - 96, 218, 159, 44, 41, 40, 94, 247, 147, 11, 255, 68, 40, 177, - ], - }, - inclusion_proof: vec![ - 203, 160, 237, 48, 117, 255, 75, 254, 117, 144, 164, 77, 29, 146, 36, 48, 190, 140, - 50, 100, 144, 237, 125, 125, 75, 54, 210, 247, 147, 23, 48, 189, 120, 4, 125, 123, - 195, 244, 207, 239, 145, 109, 0, 21, 11, 162, 109, 79, 192, 100, 138, 157, 203, 22, - 17, 114, 234, 72, 174, 231, 209, 133, 99, 118, 201, 160, 137, 128, 112, 84, 34, - 136, 174, 139, 96, 26, 246, 148, 134, 52, 200, 229, 160, 145, 5, 120, 18, 187, 51, - 11, 109, 91, 237, 171, 215, 207, 90, 95, 146, 54, 135, 166, 66, 157, 255, 237, 69, - 183, 141, 45, 162, 145, 71, 16, 87, 184, 120, 84, 156, 220, 159, 4, 99, 48, 191, - 203, 136, 112, 127, 226, 192, 184, 110, 6, 177, 182, 109, 207, 197, 239, 161, 132, - 17, 89, 56, 137, 205, 202, 101, 97, 60, 162, 253, 23, 169, 75, 236, 211, 126, 121, - 132, 191, 68, 167, 200, 16, 154, 149, 202, 197, 7, 191, 26, 8, 67, 3, 37, 137, 16, - 153, 30, 209, 238, 53, 233, 148, 198, 253, 94, 216, 73, 25, 190, 205, 132, 208, - 255, 219, 170, 98, 17, 160, 179, 183, 200, 17, 99, 36, 130, 216, 223, 72, 222, 250, - 73, 78, 79, 72, 253, 105, 245, 84, 244, 196, - ], - quorum_indexes: vec![0, 1], - }, - }; - let result = verifier.verify_security_params(&cert).await; - assert!(result.is_ok()); -} diff --git a/core/node/node_framework/src/implementations/layers/da_clients/eigen.rs b/core/node/node_framework/src/implementations/layers/da_clients/eigen.rs index 648ed6d9e8b3..1c532f263109 100644 --- a/core/node/node_framework/src/implementations/layers/da_clients/eigen.rs +++ b/core/node/node_framework/src/implementations/layers/da_clients/eigen.rs @@ -1,6 +1,9 @@ +use std::{error::Error, sync::Arc}; + use zksync_config::{configs::da_client::eigen::EigenSecrets, EigenConfig}; use zksync_da_client::DataAvailabilityClient; -use zksync_da_clients::eigen::EigenDAClient; +use zksync_da_clients::eigen::{EigenDAClient, GetBlobData}; +use zksync_dal::{ConnectionPool, Core, CoreDal}; use zksync_node_framework_derive::FromContext; use crate::{ @@ -47,10 +50,10 @@ impl WiringLayer for EigenWiringLayer { async fn wire(self, input: Self::Input) -> Result { let master_pool = input.master_pool.get().await?; - // let get_blob_from_db = GetBlobFromDB { pool: master_pool }; // TODO: should be this - let client: Box = - Box::new(EigenDAClient::new(self.config, self.secrets, master_pool).await?); - // Box::new(EigenDAClient::new(self.config, self.secrets, Arc::new(get_blob_from_db)).await?); // TODO: should be this + let get_blob_from_db = GetBlobFromDB { pool: master_pool }; // TODO: should be this + let client: Box = Box::new( + EigenDAClient::new(self.config, self.secrets, Arc::new(get_blob_from_db)).await?, + ); // TODO: should be this Ok(Self::Output { client: DAClientResource(client), @@ -58,25 +61,22 @@ impl WiringLayer for EigenWiringLayer { } } -// TODO: RE-ADD -// #[derive(Debug, Clone)] -// pub struct GetBlobFromDB { -// pool: ConnectionPool, -// } - -// TODO: RE-ADD -// #[async_trait::async_trait] -// impl GetBlobData for GetBlobFromDB { -// async fn get_blob_data(&self, input: &str) -> anyhow::Result>> { -// let mut conn = self.pool.connection_tagged("eigen_client").await?; -// let batch = conn -// .data_availability_dal() -// .get_blob_data_by_blob_id(input) -// .await?; -// Ok(batch.map(|b| b.pubdata)) -// } +#[derive(Debug, Clone)] +pub struct GetBlobFromDB { + pool: ConnectionPool, +} -// fn clone_boxed(&self) -> Box { -// Box::new(self.clone()) -// } -// } +#[async_trait::async_trait] +impl GetBlobData for GetBlobFromDB { + async fn get_blob_data( + &self, + input: &str, + ) -> Result>, Box> { + let mut conn = self.pool.connection_tagged("eigen_client").await?; + let batch = conn + .data_availability_dal() + .get_blob_data_by_blob_id(input) + .await?; + Ok(batch.map(|b| b.pubdata)) + } +}