From cef9a89328f4b66cdfe3e337aeb980ea36fb13d9 Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Thu, 28 Nov 2024 16:23:57 -0300 Subject: [PATCH] feat(eigen-client-extra-features): Add option to download points (#361) * Add option to download points * Fix test * Fix clippy * Change name to points source * Fix test * Fix test --- .../lib/config/src/configs/da_client/eigen.rs | 16 +++- core/lib/env_config/src/da_client.rs | 55 ++++++++++--- core/lib/protobuf_config/src/da_client.rs | 32 ++++++-- .../src/proto/config/da_client.proto | 15 +++- core/node/da_clients/src/eigen/client.rs | 11 +-- .../src/eigen/eigenda-integration.md | 3 +- core/node/da_clients/src/eigen/sdk.rs | 3 +- core/node/da_clients/src/eigen/verifier.rs | 79 ++++++++++++++----- 8 files changed, 166 insertions(+), 48 deletions(-) diff --git a/core/lib/config/src/configs/da_client/eigen.rs b/core/lib/config/src/configs/da_client/eigen.rs index a07d932d3dc8..b39365bced2b 100644 --- a/core/lib/config/src/configs/da_client/eigen.rs +++ b/core/lib/config/src/configs/da_client/eigen.rs @@ -1,5 +1,17 @@ use serde::Deserialize; use zksync_basic_types::secrets::PrivateKey; + +#[derive(Clone, Debug, PartialEq, Deserialize)] +pub enum PointsSource { + Path(String), + Link(String), +} + +impl Default for PointsSource { + fn default() -> Self { + PointsSource::Path("".to_string()) + } +} /// Configuration for the EigenDA remote disperser client. #[derive(Clone, Debug, PartialEq, Deserialize, Default)] pub struct EigenConfig { @@ -22,8 +34,8 @@ pub struct EigenConfig { pub authenticated: bool, /// Verify the certificate of dispatched blobs pub verify_cert: bool, - /// Path to the file containing the points used for KZG - pub path_to_points: String, + /// Path or link to the file containing the points used for KZG + pub points_source: PointsSource, /// Chain ID of the Ethereum network pub chain_id: u64, } diff --git a/core/lib/env_config/src/da_client.rs b/core/lib/env_config/src/da_client.rs index 8cd7658cd1db..70bf61a6332f 100644 --- a/core/lib/env_config/src/da_client.rs +++ b/core/lib/env_config/src/da_client.rs @@ -1,17 +1,21 @@ use std::env; -use zksync_config::configs::{ - da_client::{ - avail::{ - AvailClientConfig, AvailSecrets, AVAIL_FULL_CLIENT_NAME, AVAIL_GAS_RELAY_CLIENT_NAME, +use zksync_config::{ + configs::{ + da_client::{ + avail::{ + AvailClientConfig, AvailSecrets, AVAIL_FULL_CLIENT_NAME, + AVAIL_GAS_RELAY_CLIENT_NAME, + }, + celestia::CelestiaSecrets, + eigen::EigenSecrets, + DAClientConfig, AVAIL_CLIENT_CONFIG_NAME, CELESTIA_CLIENT_CONFIG_NAME, + EIGEN_CLIENT_CONFIG_NAME, OBJECT_STORE_CLIENT_CONFIG_NAME, }, - celestia::CelestiaSecrets, - eigen::EigenSecrets, - DAClientConfig, AVAIL_CLIENT_CONFIG_NAME, CELESTIA_CLIENT_CONFIG_NAME, - EIGEN_CLIENT_CONFIG_NAME, OBJECT_STORE_CLIENT_CONFIG_NAME, + secrets::DataAvailabilitySecrets, + AvailConfig, }, - secrets::DataAvailabilitySecrets, - AvailConfig, + EigenConfig, }; use crate::{envy_load, FromEnv}; @@ -34,7 +38,30 @@ impl FromEnv for DAClientConfig { }, }), CELESTIA_CLIENT_CONFIG_NAME => Self::Celestia(envy_load("da_celestia_config", "DA_")?), - EIGEN_CLIENT_CONFIG_NAME => Self::Eigen(envy_load("da_eigen_config", "DA_")?), + EIGEN_CLIENT_CONFIG_NAME => Self::Eigen(EigenConfig { + disperser_rpc: env::var("DA_DISPERSER_RPC")?, + settlement_layer_confirmation_depth: env::var( + "DA_SETTLEMENT_LAYER_CONFIRMATION_DEPTH", + )? + .parse()?, + eigenda_eth_rpc: env::var("DA_EIGENDA_ETH_RPC")?, + eigenda_svc_manager_address: env::var("DA_EIGENDA_SVC_MANAGER_ADDRESS")?, + status_query_timeout: env::var("DA_STATUS_QUERY_TIMEOUT")?.parse()?, + status_query_interval: env::var("DA_STATUS_QUERY_INTERVAL")?.parse()?, + wait_for_finalization: env::var("DA_WAIT_FOR_FINALIZATION")?.parse()?, + authenticated: env::var("DA_AUTHENTICATED")?.parse()?, + verify_cert: env::var("DA_VERIFY_CERT")?.parse()?, + points_source: match env::var("DA_POINTS_SOURCE")?.as_str() { + "Path" => zksync_config::configs::da_client::eigen::PointsSource::Path( + env::var("DA_POINTS_PATH")?, + ), + "Link" => zksync_config::configs::da_client::eigen::PointsSource::Link( + env::var("DA_POINTS_LINK")?, + ), + _ => anyhow::bail!("Unknown Eigen points type"), + }, + chain_id: env::var("DA_CHAIN_ID")?.parse()?, + }), OBJECT_STORE_CLIENT_CONFIG_NAME => { Self::ObjectStore(envy_load("da_object_store", "DA_")?) } @@ -94,6 +121,7 @@ mod tests { configs::{ da_client::{ avail::{AvailClientConfig, AvailDefaultConfig}, + eigen::PointsSource, DAClientConfig::{self, ObjectStore}, }, object_store::ObjectStoreMode::GCS, @@ -258,7 +286,8 @@ mod tests { DA_WAIT_FOR_FINALIZATION=true DA_AUTHENTICATED=false DA_VERIFY_CERT=false - DA_PATH_TO_POINTS="resources" + DA_POINTS_SOURCE="Path" + DA_POINTS_PATH="resources" DA_CHAIN_ID=1 "#; lock.set_env(config); @@ -276,7 +305,7 @@ mod tests { wait_for_finalization: true, authenticated: false, verify_cert: false, - path_to_points: "resources".to_string(), + points_source: PointsSource::Path("resources".to_string()), chain_id: 1 }) ); diff --git a/core/lib/protobuf_config/src/da_client.rs b/core/lib/protobuf_config/src/da_client.rs index 210171be1875..19caf970becb 100644 --- a/core/lib/protobuf_config/src/da_client.rs +++ b/core/lib/protobuf_config/src/da_client.rs @@ -10,7 +10,10 @@ use zksync_config::configs::{ }; use zksync_protobuf::{required, ProtoRepr}; -use crate::proto::{da_client as proto, object_store as object_store_proto}; +use crate::proto::{ + da_client::{self as proto, Link, Path}, + object_store as object_store_proto, +}; impl ProtoRepr for proto::DataAvailabilityClient { type Type = configs::DAClientConfig; @@ -74,9 +77,17 @@ impl ProtoRepr for proto::DataAvailabilityClient { .context("wait_for_finalization")?, authenticated: *required(&conf.authenticated).context("authenticated")?, verify_cert: *required(&conf.verify_cert).context("verify_cert")?, - path_to_points: required(&conf.path_to_points) - .context("path_to_points")? - .clone(), + points_source: match conf.points_source.clone() { + Some(proto::eigen_config::PointsSource::Path(path)) => { + let path = required(&path.path).context("path")?; + zksync_config::configs::da_client::eigen::PointsSource::Path(path.clone()) + } + Some(proto::eigen_config::PointsSource::Link(link)) => { + let link = required(&link.link).context("link")?; + zksync_config::configs::da_client::eigen::PointsSource::Link(link.clone()) + } + None => return Err(anyhow::anyhow!("Invalid Eigen DA configuration")), + }, chain_id: *required(&conf.chain_id).context("chain_id")?, }), proto::data_availability_client::Config::ObjectStore(conf) => { @@ -127,7 +138,18 @@ impl ProtoRepr for proto::DataAvailabilityClient { wait_for_finalization: Some(config.wait_for_finalization), authenticated: Some(config.authenticated), verify_cert: Some(config.verify_cert), - path_to_points: Some(config.path_to_points.clone()), + points_source: Some(match &config.points_source { + zksync_config::configs::da_client::eigen::PointsSource::Path(path) => { + proto::eigen_config::PointsSource::Path(Path { + path: Some(path.to_string()), + }) + } + zksync_config::configs::da_client::eigen::PointsSource::Link(link) => { + proto::eigen_config::PointsSource::Link(Link { + link: Some(link.to_string()), + }) + } + }), chain_id: Some(config.chain_id), }), ObjectStore(config) => proto::data_availability_client::Config::ObjectStore( diff --git a/core/lib/protobuf_config/src/proto/config/da_client.proto b/core/lib/protobuf_config/src/proto/config/da_client.proto index 8463629b3240..05408a8aa751 100644 --- a/core/lib/protobuf_config/src/proto/config/da_client.proto +++ b/core/lib/protobuf_config/src/proto/config/da_client.proto @@ -36,6 +36,14 @@ message CelestiaConfig { optional uint64 timeout_ms = 4; } +message Path { + optional string path = 1; +} + +message Link { + optional string link = 1; +} + message EigenConfig { optional string disperser_rpc = 3; optional int32 settlement_layer_confirmation_depth = 4; @@ -46,8 +54,11 @@ message EigenConfig { optional bool wait_for_finalization = 9; optional bool authenticated = 10; optional bool verify_cert = 11; - optional string path_to_points = 12; - optional uint64 chain_id = 13; + oneof points_source { + Path path = 12; + Link link = 13; + } + optional uint64 chain_id = 14; reserved 1,2; reserved "rpc_node_url","inclusion_polling_interval_ms"; } diff --git a/core/node/da_clients/src/eigen/client.rs b/core/node/da_clients/src/eigen/client.rs index 1066065adc10..2f0138ff2014 100644 --- a/core/node/da_clients/src/eigen/client.rs +++ b/core/node/da_clients/src/eigen/client.rs @@ -92,6 +92,7 @@ impl EigenClient { #[cfg(test)] mod tests { use serial_test::serial; + use zksync_config::configs::da_client::eigen::PointsSource; use zksync_types::secrets::PrivateKey; use super::*; @@ -110,7 +111,7 @@ mod tests { wait_for_finalization: false, authenticated: false, verify_cert: true, - path_to_points: "../../../resources".to_string(), + points_source: PointsSource::Path("../../../resources".to_string()), chain_id: 17000, }; let secrets = EigenSecrets { @@ -152,7 +153,7 @@ mod tests { wait_for_finalization: false, authenticated: true, verify_cert: true, - path_to_points: "../../../resources".to_string(), + points_source: PointsSource::Path("../../../resources".to_string()), chain_id: 17000, }; let secrets = EigenSecrets { @@ -190,7 +191,7 @@ mod tests { wait_for_finalization: true, authenticated: true, verify_cert: true, - path_to_points: "../../../resources".to_string(), + points_source: PointsSource::Path("../../../resources".to_string()), settlement_layer_confirmation_depth: 0, eigenda_eth_rpc: "https://ethereum-holesky-rpc.publicnode.com".to_string(), eigenda_svc_manager_address: "0xD4A7E1Bd8015057293f0D0A557088c286942e84b".to_string(), @@ -234,7 +235,7 @@ mod tests { wait_for_finalization: false, authenticated: false, verify_cert: true, - path_to_points: "../../../resources".to_string(), + points_source: PointsSource::Path("../../../resources".to_string()), chain_id: 17000, }; let secrets = EigenSecrets { @@ -275,7 +276,7 @@ mod tests { wait_for_finalization: false, authenticated: true, verify_cert: true, - path_to_points: "../../../resources".to_string(), + points_source: PointsSource::Path("../../../resources".to_string()), chain_id: 17000, }; let secrets = EigenSecrets { diff --git a/core/node/da_clients/src/eigen/eigenda-integration.md b/core/node/da_clients/src/eigen/eigenda-integration.md index e15178e0fcfc..7ff92c67a7d9 100644 --- a/core/node/da_clients/src/eigen/eigenda-integration.md +++ b/core/node/da_clients/src/eigen/eigenda-integration.md @@ -29,7 +29,8 @@ da_client: wait_for_finalization: false authenticated: false verify_cert: true - path_to_points: ./resources + link: + link: chain_id: ``` diff --git a/core/node/da_clients/src/eigen/sdk.rs b/core/node/da_clients/src/eigen/sdk.rs index 208a2f138c7e..a847d874fbec 100644 --- a/core/node/da_clients/src/eigen/sdk.rs +++ b/core/node/da_clients/src/eigen/sdk.rs @@ -52,13 +52,14 @@ impl RawEigenClient { rpc_url: config.eigenda_eth_rpc.clone(), svc_manager_addr: config.eigenda_svc_manager_address.clone(), max_blob_size: Self::BLOB_SIZE_LIMIT as u32, - path_to_points: config.path_to_points.clone(), + points: config.points_source.clone(), settlement_layer_confirmation_depth: config.settlement_layer_confirmation_depth.max(0) as u32, private_key: hex::encode(private_key.secret_bytes()), chain_id: config.chain_id, }; let verifier = Verifier::new(verifier_config) + .await .map_err(|e| anyhow::anyhow!(format!("Failed to create verifier {:?}", e)))?; Ok(RawEigenClient { client, diff --git a/core/node/da_clients/src/eigen/verifier.rs b/core/node/da_clients/src/eigen/verifier.rs index b505f6f3c2d3..8c9f971fe37d 100644 --- a/core/node/da_clients/src/eigen/verifier.rs +++ b/core/node/da_clients/src/eigen/verifier.rs @@ -1,10 +1,11 @@ -use std::{collections::HashMap, str::FromStr}; +use std::{collections::HashMap, fs::File, io::copy, path::Path, str::FromStr}; use ark_bn254::{Fq, G1Affine}; use ethabi::{encode, Token}; use rust_kzg_bn254::{blob::Blob, kzg::Kzg, polynomial::PolynomialFormat}; use tiny_keccak::{Hasher, Keccak}; use zksync_basic_types::web3::CallRequest; +use zksync_config::configs::da_client::eigen::PointsSource; use zksync_eth_client::clients::PKSigningClient; use zksync_types::{ url::SensitiveUrl, @@ -36,6 +37,7 @@ pub enum VerificationError { QuorumNotConfirmed, CommitmentNotOnCurve, CommitmentNotOnCorrectSubgroup, + LinkError, } /// Configuration for the verifier used for authenticated dispersals @@ -44,7 +46,7 @@ pub struct VerifierConfig { pub rpc_url: String, pub svc_manager_addr: String, pub max_blob_size: u32, - pub path_to_points: String, + pub points: PointsSource, pub settlement_layer_confirmation_depth: u32, pub private_key: String, pub chain_id: u64, @@ -62,12 +64,43 @@ pub struct Verifier { impl Verifier { const DEFAULT_PRIORITY_FEE_PER_GAS: u64 = 100; - pub fn new(cfg: VerifierConfig) -> Result { + async fn save_points(link: String) -> Result { + let url_g1 = format!("{}{}", link, "/g1.point"); + let response = reqwest::get(url_g1) + .await + .map_err(|_| VerificationError::LinkError)?; + let path = Path::new("./g1.point"); + let mut file = File::create(path).map_err(|_| VerificationError::LinkError)?; + let content = response + .bytes() + .await + .map_err(|_| VerificationError::LinkError)?; + copy(&mut content.as_ref(), &mut file).map_err(|_| VerificationError::LinkError)?; + + let url_g2 = format!("{}{}", link, "/g2.point.powerOf2"); + let response = reqwest::get(url_g2) + .await + .map_err(|_| VerificationError::LinkError)?; + let path = Path::new("./g2.point.powerOf2"); + let mut file = File::create(path).map_err(|_| VerificationError::LinkError)?; + let content = response + .bytes() + .await + .map_err(|_| VerificationError::LinkError)?; + copy(&mut content.as_ref(), &mut file).map_err(|_| VerificationError::LinkError)?; + + Ok(".".to_string()) + } + pub async fn new(cfg: VerifierConfig) -> Result { let srs_points_to_load = cfg.max_blob_size / 32; + let path = match cfg.points.clone() { + PointsSource::Path(path) => path, + PointsSource::Link(link) => Self::save_points(link).await?, + }; let kzg = Kzg::setup( - &format!("{}{}", cfg.path_to_points, "/g1.point"), + &format!("{}{}", path, "/g1.point"), "", - &format!("{}{}", cfg.path_to_points, "/g2.point.powerOf2"), + &format!("{}{}", path, "/g2.point.powerOf2"), 268435456, // 2 ^ 28 srs_points_to_load, "".to_string(), @@ -478,23 +511,26 @@ impl Verifier { #[cfg(test)] mod test { + use zksync_config::configs::da_client::eigen::PointsSource; + use crate::eigen::blob_info::{ BatchHeader, BatchMetadata, BlobHeader, BlobInfo, BlobQuorumParam, BlobVerificationProof, G1Commitment, }; - #[test] - fn test_verify_commitment() { + #[tokio::test] + async fn test_verify_commitment() { let verifier = super::Verifier::new(super::VerifierConfig { rpc_url: "https://ethereum-holesky-rpc.publicnode.com".to_string(), svc_manager_addr: "0xD4A7E1Bd8015057293f0D0A557088c286942e84b".to_string(), max_blob_size: 2 * 1024 * 1024, - path_to_points: "../../../resources".to_string(), + points: PointsSource::Path("../../../resources".to_string()), settlement_layer_confirmation_depth: 0, private_key: "0xd08aa7ae1bb5ddd46c3c2d8cdb5894ab9f54dec467233686ca42629e826ac4c6" .to_string(), chain_id: 17000, }) + .await .unwrap(); let commitment = G1Commitment { x: vec![ @@ -511,18 +547,19 @@ mod test { assert!(result.is_ok()); } - #[test] - fn test_verify_merkle_proof() { + #[tokio::test] + async fn test_verify_merkle_proof() { let verifier = super::Verifier::new(super::VerifierConfig { rpc_url: "https://ethereum-holesky-rpc.publicnode.com".to_string(), svc_manager_addr: "0xD4A7E1Bd8015057293f0D0A557088c286942e84b".to_string(), max_blob_size: 2 * 1024 * 1024, - path_to_points: "../../../resources".to_string(), + points: PointsSource::Path("../../../resources".to_string()), settlement_layer_confirmation_depth: 0, private_key: "0xd08aa7ae1bb5ddd46c3c2d8cdb5894ab9f54dec467233686ca42629e826ac4c6" .to_string(), chain_id: 17000, }) + .await .unwrap(); let cert = BlobInfo { blob_header: BlobHeader { @@ -600,18 +637,19 @@ mod test { assert!(result.is_ok()); } - #[test] - fn test_hash_blob_header() { + #[tokio::test] + async fn test_hash_blob_header() { let verifier = super::Verifier::new(super::VerifierConfig { rpc_url: "https://ethereum-holesky-rpc.publicnode.com".to_string(), svc_manager_addr: "0xD4A7E1Bd8015057293f0D0A557088c286942e84b".to_string(), max_blob_size: 2 * 1024 * 1024, - path_to_points: "../../../resources".to_string(), + points: PointsSource::Path("../../../resources".to_string()), settlement_layer_confirmation_depth: 0, private_key: "0xd08aa7ae1bb5ddd46c3c2d8cdb5894ab9f54dec467233686ca42629e826ac4c6" .to_string(), chain_id: 17000, }) + .await .unwrap(); let blob_header = BlobHeader { commitment: G1Commitment { @@ -645,18 +683,19 @@ mod test { assert_eq!(result, hex::decode(expected).unwrap()); } - #[test] - fn test_inclusion_proof() { + #[tokio::test] + async fn test_inclusion_proof() { let verifier = super::Verifier::new(super::VerifierConfig { rpc_url: "https://ethereum-holesky-rpc.publicnode.com".to_string(), svc_manager_addr: "0xD4A7E1Bd8015057293f0D0A557088c286942e84b".to_string(), max_blob_size: 2 * 1024 * 1024, - path_to_points: "../../../resources".to_string(), + points: PointsSource::Path("../../../resources".to_string()), settlement_layer_confirmation_depth: 0, private_key: "0xd08aa7ae1bb5ddd46c3c2d8cdb5894ab9f54dec467233686ca42629e826ac4c6" .to_string(), chain_id: 17000, }) + .await .unwrap(); let proof = hex::decode("c455c1ea0e725d7ea3e5f29e9f48be8fc2787bb0a914d5a86710ba302c166ac4f626d76f67f1055bb960a514fb8923af2078fd84085d712655b58a19612e8cd15c3e4ac1cef57acde3438dbcf63f47c9fefe1221344c4d5c1a4943dd0d1803091ca81a270909dc0e146841441c9bd0e08e69ce6168181a3e4060ffacf3627480bec6abdd8d7bb92b49d33f180c42f49e041752aaded9c403db3a17b85e48a11e9ea9a08763f7f383dab6d25236f1b77c12b4c49c5cdbcbea32554a604e3f1d2f466851cb43fe73617b3d01e665e4c019bf930f92dea7394c25ed6a1e200d051fb0c30a2193c459f1cfef00bf1ba6656510d16725a4d1dc031cb759dbc90bab427b0f60ddc6764681924dda848824605a4f08b7f526fe6bd4572458c94e83fbf2150f2eeb28d3011ec921996dc3e69efa52d5fcf3182b20b56b5857a926aa66605808079b4d52c0c0cfe06923fa92e65eeca2c3e6126108e8c1babf5ac522f4d7").unwrap(); @@ -679,12 +718,13 @@ mod test { rpc_url: "https://ethereum-holesky-rpc.publicnode.com".to_string(), svc_manager_addr: "0xD4A7E1Bd8015057293f0D0A557088c286942e84b".to_string(), max_blob_size: 2 * 1024 * 1024, - path_to_points: "../../../resources".to_string(), + points: PointsSource::Path("../../../resources".to_string()), settlement_layer_confirmation_depth: 0, private_key: "0xd08aa7ae1bb5ddd46c3c2d8cdb5894ab9f54dec467233686ca42629e826ac4c6" .to_string(), chain_id: 17000, }) + .await .unwrap(); let cert = BlobInfo { blob_header: BlobHeader { @@ -768,12 +808,13 @@ mod test { rpc_url: "https://ethereum-holesky-rpc.publicnode.com".to_string(), svc_manager_addr: "0xD4A7E1Bd8015057293f0D0A557088c286942e84b".to_string(), max_blob_size: 2 * 1024 * 1024, - path_to_points: "../../../resources".to_string(), + points: PointsSource::Path("../../../resources".to_string()), settlement_layer_confirmation_depth: 0, private_key: "0xd08aa7ae1bb5ddd46c3c2d8cdb5894ab9f54dec467233686ca42629e826ac4c6" .to_string(), chain_id: 17000, }) + .await .unwrap(); let cert = BlobInfo { blob_header: BlobHeader {