Skip to content

Commit 8302a81

Browse files
gianbelinchejuan518munozjuanbono
authored
feat(eigenda): EigenDA V2 M0 (#3983)
## What ❔ This PR modifies the client for EigenDA, adding the option to use EigenDA V2. It replaces the old v1 crate `rust-eigenda-client` for the new v2 crate `rust-eigenda-v2-client`. It modifies the `EigenConfig` to leave only the necessary fields for v2. It removes: - `settlement_layer_confirmation_depth` - `eigenda_svc_manager_address` - `wait_for_finalization` - `points` - `custom_quorum_numbers` It adds: - `cert_verifier_router_addr` - `blob_version` - `polynomial_form` - `operator_state_retriever_addr` - `registry_coordinator_addr` The client now uses a `PayloadDisperser` to disperse the blobs, with the `send_payload` method. And uses the `get_cert` method to get the inclusion data. How to test: ```bash zkstackup --local ``` Modify `etc/env/file_based/overrides/validium.yaml`: ```yaml da_dispatcher: use_dummy_inclusion_data: true da_client: client: Eigen disperser_rpc: <your_disperser_rpc> eigenda_eth_rpc: <your_eth_rpc> authenticated: true cert_verifier_router_addr: <your_cert_verifier_address> operator_state_retriever_addr: <your_operator_state_retriever_addr> registry_coordinator_addr: <your_registry_coordinator_addr> blob_version: <your_blob_version> polynomial_form: <your_polynomial_form> #Either coeff or eval ``` Modify `etc/env/file_based/secrets.yaml`: ```yaml da: client: Eigen private_key: <your_private_key> #The private key you want to use with the eigenda disperser ``` Run replacing with your l1 rpc: ```bash zkstack containers --observability true zkstack chain create \ --chain-name eigenda \ --chain-id sequential \ --prover-mode no-proofs \ --wallet-creation localhost \ --l1-batch-commit-data-generator-mode validium \ --base-token-address 0x0000000000000000000000000000000000000001 \ --base-token-price-nominator 1 \ --base-token-price-denominator 1 \ --set-as-default false zkstack ecosystem init \ --deploy-paymaster true \ --deploy-erc20 true \ --deploy-ecosystem true \ --l1-rpc-url <your_l1_rpc> \ --server-db-url=postgres://postgres:notsecurepassword@localhost:5432 \ --server-db-name=zksync_server_localhost_eigenda \ --chain eigenda \ --verbose ``` Then run ```bash zkstack server --chain eigenda ``` <!-- What are the changes this PR brings about? --> <!-- Example: This PR adds a PR template to the repo. --> <!-- (For bigger PRs adding more context is appreciated) --> ## Why ❔ To support the latest version of EigenDA (V2 M0), while preserving compatibility with the existing client (V1 M0). <!-- Why are these changes done? What goal do they contribute to? What are the principles behind them? --> <!-- The `Why` has to be clear to non-Matter Labs entities running their own ZK Chain --> <!-- Example: PR templates ensure PR reviewers, observers, and future iterators are in context about the evolution of repos. --> ## Is this a breaking change? - [x] Yes - [ ] No ## Operational changes <!-- Any config changes? Any new flags? Any changes to any scripts? --> <!-- Please add anything that non-Matter Labs entities running their own ZK Chain may need to know --> ## Checklist <!-- Check your PR fulfills the following items. --> <!-- For draft PRs check the boxes as you complete them. --> - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zkstack dev fmt` and `zkstack dev lint`. --------- Co-authored-by: juan518munoz <[email protected]> Co-authored-by: Juan Munoz <[email protected]> Co-authored-by: Juan Bono <[email protected]>
1 parent 1f668e5 commit 8302a81

File tree

18 files changed

+2552
-1117
lines changed

18 files changed

+2552
-1117
lines changed

core/Cargo.lock

Lines changed: 2289 additions & 842 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,10 @@ ripemd = "0.1.3"
238238
tonic = { version = "0.11.0", default-features = false }
239239
pbjson-types = "0.6.0"
240240

241-
# Eigen
242-
rust-eigenda-client = "0.1.6"
241+
# EigenDA
242+
rust-eigenda-v2-client = "=0.1.4"
243+
rust-eigenda-v2-common = "=0.1.3"
244+
rust-eigenda-signers = "0.1.6"
243245

244246
# Here and below:
245247
# We *always* pin the latest version of protocol to disallow accidental changes in the execution logic.

core/bin/external_node/src/config/tests/mod.rs

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use smart_config::{testing::Tester, value::ExposeSecret, ByteSize, ConfigSource,
1414
use zksync_config::{
1515
configs::{
1616
api::{MaxResponseSizeOverrides, Namespace},
17-
da_client::{avail::AvailClientConfig, eigen::PointsSource},
17+
da_client::avail::AvailClientConfig,
1818
database::MerkleTreeMode,
1919
object_store::ObjectStoreMode,
2020
observability::LogFormat,
@@ -647,14 +647,11 @@ fn eigen_da_client_from_env() {
647647
let env = r#"
648648
EN_DA_CLIENT="Eigen"
649649
EN_DA_DISPERSER_RPC="http://localhost:8080"
650-
EN_DA_SETTLEMENT_LAYER_CONFIRMATION_DEPTH=0
651650
EN_DA_EIGENDA_ETH_RPC="http://localhost:8545"
652-
EN_DA_EIGENDA_SVC_MANAGER_ADDRESS="0x0000000000000000000000000000000000000123"
653-
EN_DA_WAIT_FOR_FINALIZATION=true
654-
EN_DA_AUTHENTICATED=false
655-
EN_DA_POINTS_SOURCE="Path"
656-
EN_DA_POINTS_PATH="resources"
657-
EN_DA_CUSTOM_QUORUM_NUMBERS="2"
651+
EN_DA_CERT_VERIFIER_ROUTER_ADDR="0x0000000000000000000000000000000000000123"
652+
EN_DA_OPERATOR_STATE_RETRIEVER_ADDR="0x0000000000000000000000000000000000000124"
653+
EN_DA_REGISTRY_COORDINATOR_ADDR="0x0000000000000000000000000000000000000125"
654+
EN_DA_BLOB_VERSION="0"
658655
659656
# Secrets
660657
EN_DA_SECRETS_PRIVATE_KEY="f55baf7c0e4e33b1d78fbf52f069c426bc36cff1aceb9bc8f45d14c07f034d73"
@@ -671,24 +668,23 @@ fn eigen_da_client_from_env() {
671668
panic!("unexpected config: {config:?}");
672669
};
673670
assert_eq!(config.disperser_rpc, "http://localhost:8080");
674-
assert_eq!(config.settlement_layer_confirmation_depth, 0);
675671
assert_eq!(
676672
config.eigenda_eth_rpc.as_ref().unwrap().expose_str(),
677673
"http://localhost:8545/"
678674
);
675+
assert_eq!(config.blob_version, 0);
679676
assert_eq!(
680-
config.eigenda_svc_manager_address,
677+
config.cert_verifier_router_addr,
681678
"0x0000000000000000000000000000000000000123"
682-
.parse()
683-
.unwrap()
684679
);
685-
assert!(config.wait_for_finalization);
686-
assert!(!config.authenticated);
687-
let PointsSource::Path { path } = &config.points else {
688-
panic!("unexpected points: {config:?}");
689-
};
690-
assert_eq!(path, "resources");
691-
assert_eq!(config.custom_quorum_numbers, [2]);
680+
assert_eq!(
681+
config.operator_state_retriever_addr,
682+
"0x0000000000000000000000000000000000000124"
683+
);
684+
assert_eq!(
685+
config.registry_coordinator_addr,
686+
"0x0000000000000000000000000000000000000125"
687+
);
692688

693689
let secrets: DataAvailabilitySecrets = tester.for_config().test_complete(env.clone()).unwrap();
694690
let DataAvailabilitySecrets::Eigen(secrets) = secrets else {

core/deny.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ allow = [
3333
"Apache-2.0 WITH LLVM-exception",
3434
"0BSD",
3535
"BSL-1.0",
36-
"Unicode-3.0"
36+
"Unicode-3.0",
37+
"BUSL-1.1",
38+
"CDLA-Permissive-2.0"
3739
]
3840
confidence-threshold = 0.8
3941

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,35 @@
1+
use serde::Deserialize;
12
use smart_config::{
2-
de::{Delimited, FromSecretString, Optional, Serde},
3+
de::{FromSecretString, Optional, Serde},
34
DescribeConfig, DeserializeConfig,
45
};
5-
use zksync_basic_types::{secrets::PrivateKey, url::SensitiveUrl, Address};
6-
7-
#[derive(Clone, Debug, PartialEq, DescribeConfig, DeserializeConfig)]
8-
#[config(tag = "source")]
9-
pub enum PointsSource {
10-
Path { path: String },
11-
Url { g1_url: String, g2_url: String },
12-
}
6+
use zksync_basic_types::{secrets::PrivateKey, url::SensitiveUrl};
137

148
/// Configuration for the EigenDA remote disperser client.
15-
#[derive(Clone, Debug, PartialEq, DescribeConfig, DeserializeConfig)]
9+
///
10+
/// This configuration is meant to be used by the EigenDA V2 client.
11+
/// It is an insecure integration, where the dispersal is not verified.
12+
#[derive(Clone, Debug, PartialEq, Deserialize, DescribeConfig, DeserializeConfig)]
1613
pub struct EigenConfig {
1714
/// URL of the Disperser RPC server
1815
pub disperser_rpc: String,
19-
/// Block height needed to reach in order to consider the blob finalized
20-
/// a value less or equal to 0 means that the disperser will not wait for finalization
21-
#[config(default_t = 0)]
22-
pub settlement_layer_confirmation_depth: u32,
2316
/// URL of the Ethereum RPC server
2417
#[config(secret, with = Optional(Serde![str]))]
2518
pub eigenda_eth_rpc: Option<SensitiveUrl>,
26-
/// Address of the service manager contract
27-
pub eigenda_svc_manager_address: Address,
28-
/// Wait for the blob to be finalized before returning the response
29-
#[config(default_t = true)]
30-
pub wait_for_finalization: bool,
31-
/// Authenticated dispersal
32-
#[config(default_t = true)]
33-
pub authenticated: bool,
34-
/// Points source
35-
#[config(nest)]
36-
pub points: PointsSource,
37-
/// Custom quorum numbers
38-
#[config(default, with = Delimited(","))]
39-
pub custom_quorum_numbers: Vec<u8>,
19+
/// Address of the EigenDA cert verifier router
20+
pub cert_verifier_router_addr: String,
21+
/// Blob version
22+
pub blob_version: u16,
23+
/// Address of the operator state retriever
24+
pub operator_state_retriever_addr: String,
25+
/// Address of the registry coordinator
26+
pub registry_coordinator_addr: String,
4027
}
4128

29+
/// Configuration for the EigenDA secrets.
4230
#[derive(Clone, Debug, DescribeConfig, DeserializeConfig)]
4331
pub struct EigenSecrets {
32+
/// Private key used for dispersing the blobs
4433
#[config(with = FromSecretString)]
4534
pub private_key: PrivateKey,
4635
}

core/lib/config/src/configs/da_client/mod.rs

Lines changed: 41 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ mod tests {
3333
ConfigRepository, ConfigSchema, Environment, Yaml,
3434
};
3535

36-
use super::{avail::AvailClientConfig, eigen::PointsSource, *};
36+
use super::{avail::AvailClientConfig, *};
3737
use crate::configs::{object_store::ObjectStoreMode, DataAvailabilitySecrets, Secrets};
3838

3939
#[test]
@@ -295,14 +295,11 @@ mod tests {
295295
let env = r#"
296296
DA_CLIENT="Eigen"
297297
DA_DISPERSER_RPC="http://localhost:8080"
298-
DA_SETTLEMENT_LAYER_CONFIRMATION_DEPTH=0
299298
DA_EIGENDA_ETH_RPC="http://localhost:8545"
300-
DA_EIGENDA_SVC_MANAGER_ADDRESS="0x0000000000000000000000000000000000000123"
301-
DA_WAIT_FOR_FINALIZATION=true
302-
DA_AUTHENTICATED=false
303-
DA_POINTS_SOURCE="Path"
304-
DA_POINTS_PATH="./resources"
305-
DA_CUSTOM_QUORUM_NUMBERS="2,3"
299+
DA_CERT_VERIFIER_ROUTER_ADDR="0x0000000000000000000000000000000000000123"
300+
DA_OPERATOR_STATE_RETRIEVER_ADDR="0x0000000000000000000000000000000000000124"
301+
DA_REGISTRY_COORDINATOR_ADDR="0x0000000000000000000000000000000000000125"
302+
DA_BLOB_VERSION="0"
306303
"#;
307304
let env = Environment::from_dotenv("test.env", env)
308305
.unwrap()
@@ -314,38 +311,36 @@ mod tests {
314311
};
315312

316313
assert_eq!(config.disperser_rpc, "http://localhost:8080");
317-
assert_eq!(config.settlement_layer_confirmation_depth, 0);
318314
assert_eq!(
319315
config.eigenda_eth_rpc.as_ref().unwrap().expose_str(),
320316
"http://localhost:8545/"
321317
);
322-
assert!(config.wait_for_finalization);
323-
assert!(!config.authenticated);
324318

325-
let PointsSource::Path { path } = &config.points else {
326-
panic!("Unexpected config: {config:?}");
327-
};
328-
assert_eq!(path, "./resources");
329-
assert_eq!(config.custom_quorum_numbers, [2, 3]);
319+
assert_eq!(config.blob_version, 0);
320+
assert_eq!(
321+
config.cert_verifier_router_addr,
322+
"0x0000000000000000000000000000000000000123"
323+
);
324+
assert_eq!(
325+
config.operator_state_retriever_addr,
326+
"0x0000000000000000000000000000000000000124"
327+
);
328+
assert_eq!(
329+
config.registry_coordinator_addr,
330+
"0x0000000000000000000000000000000000000125"
331+
);
330332
}
331333

332334
#[test]
333335
fn eigen_config_from_yaml() {
334336
let yaml = r#"
335-
client: Eigen
336-
disperser_rpc: https://disperser-holesky.eigenda.xyz:443
337-
settlement_layer_confirmation_depth: 1
338-
eigenda_eth_rpc: https://holesky.infura.io/
339-
eigenda_svc_manager_address: 0xD4A7E1Bd8015057293f0D0A557088c286942e84b
340-
wait_for_finalization: true
341-
authenticated: true
342-
points:
343-
source: Url
344-
g1_url: https://raw.githubusercontent.com/lambdaclass/zksync-eigenda-tools/6944c9b09ae819167ee9012ca82866b9c792d8a1/resources/g1.point
345-
g2_url: https://raw.githubusercontent.com/lambdaclass/zksync-eigenda-tools/6944c9b09ae819167ee9012ca82866b9c792d8a1/resources/g2.point.powerOf2
346-
custom_quorum_numbers:
347-
- 1
348-
- 3
337+
client: Eigen
338+
disperser_rpc: https://disperser-holesky.eigenda.xyz:443
339+
eigenda_eth_rpc: https://holesky.infura.io/
340+
cert_verifier_router_addr: "0x0000000000000000000000000000000000000123"
341+
operator_state_retriever_addr: "0x0000000000000000000000000000000000000124"
342+
registry_coordinator_addr: "0x0000000000000000000000000000000000000125"
343+
blob_version: 0
349344
"#;
350345
let yaml = Yaml::new("test.yml", serde_yaml::from_str(yaml).unwrap()).unwrap();
351346

@@ -361,40 +356,36 @@ mod tests {
361356
config.disperser_rpc,
362357
"https://disperser-holesky.eigenda.xyz:443"
363358
);
364-
assert_eq!(config.settlement_layer_confirmation_depth, 1);
365359
assert_eq!(
366360
config.eigenda_eth_rpc.as_ref().unwrap().expose_str(),
367361
"https://holesky.infura.io/"
368362
);
363+
364+
assert_eq!(config.blob_version, 0);
369365
assert_eq!(
370-
config.eigenda_svc_manager_address,
371-
"0xD4A7E1Bd8015057293f0D0A557088c286942e84b"
372-
.parse()
373-
.unwrap()
366+
config.cert_verifier_router_addr,
367+
"0x0000000000000000000000000000000000000123"
368+
);
369+
assert_eq!(
370+
config.operator_state_retriever_addr,
371+
"0x0000000000000000000000000000000000000124"
372+
);
373+
assert_eq!(
374+
config.registry_coordinator_addr,
375+
"0x0000000000000000000000000000000000000125"
374376
);
375-
assert!(config.wait_for_finalization);
376-
assert!(config.authenticated);
377-
let PointsSource::Url { g1_url, g2_url } = &config.points else {
378-
panic!("Unexpected config: {config:?}");
379-
};
380-
assert_eq!(g1_url, "https://raw.githubusercontent.com/lambdaclass/zksync-eigenda-tools/6944c9b09ae819167ee9012ca82866b9c792d8a1/resources/g1.point");
381-
assert_eq!(g2_url, "https://raw.githubusercontent.com/lambdaclass/zksync-eigenda-tools/6944c9b09ae819167ee9012ca82866b9c792d8a1/resources/g2.point.powerOf2");
382377
}
383378

384379
#[test]
385380
fn eigen_config_from_yaml_with_enum_coercion() {
386381
let yaml = r#"
387382
eigen:
388383
disperser_rpc: https://disperser-holesky.eigenda.xyz:443
389-
settlement_layer_confirmation_depth: 1
390384
eigenda_eth_rpc: https://holesky.infura.io/
391-
eigenda_svc_manager_address: 0xD4A7E1Bd8015057293f0D0A557088c286942e84b
392-
wait_for_finalization: true
393-
authenticated: true
394-
points: # This still doesn't correspond to the previous schema!
395-
url:
396-
g1_url: https://raw.githubusercontent.com/lambdaclass/zksync-eigenda-tools/6944c9b09ae819167ee9012ca82866b9c792d8a1/resources/g1.point
397-
g2_url: https://raw.githubusercontent.com/lambdaclass/zksync-eigenda-tools/6944c9b09ae819167ee9012ca82866b9c792d8a1/resources/g2.point.powerOf2
385+
blob_version: 0
386+
cert_verifier_router_addr: "0x0000000000000000000000000000000000000123"
387+
operator_state_retriever_addr: "0x0000000000000000000000000000000000000124"
388+
registry_coordinator_addr: "0x0000000000000000000000000000000000000125"
398389
"#;
399390
let yaml = Yaml::new("test.yml", serde_yaml::from_str(yaml).unwrap()).unwrap();
400391

core/lib/dal/src/data_availability_dal.rs

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -404,52 +404,6 @@ impl DataAvailabilityDal<'_, '_> {
404404
Ok(row.map(|row| L1BatchNumber(row.l1_batch_number as u32)))
405405
}
406406

407-
/// Fetches the pubdata for the L1 batch with a given blob id.
408-
pub async fn get_blob_data_by_blob_id(
409-
&mut self,
410-
blob_id: &str,
411-
) -> DalResult<Option<L1BatchDA>> {
412-
let row = sqlx::query!(
413-
r#"
414-
SELECT
415-
number,
416-
pubdata_input,
417-
system_logs,
418-
sealed_at
419-
FROM
420-
l1_batches
421-
LEFT JOIN
422-
data_availability
423-
ON data_availability.l1_batch_number = l1_batches.number
424-
WHERE
425-
number != 0
426-
AND data_availability.blob_id = $1
427-
ORDER BY
428-
number
429-
LIMIT
430-
1
431-
"#,
432-
blob_id,
433-
)
434-
.instrument("get_blob_data_by_blob_id")
435-
.with_arg("blob_id", &blob_id)
436-
.fetch_optional(self.storage)
437-
.await?
438-
.map(|row| L1BatchDA {
439-
// `unwrap` is safe here because we have a `WHERE` clause that filters out `NULL` values
440-
pubdata: row.pubdata_input.unwrap(),
441-
l1_batch_number: L1BatchNumber(row.number as u32),
442-
sealed_at: row.sealed_at.unwrap().and_utc(),
443-
system_logs: row
444-
.system_logs
445-
.into_iter()
446-
.map(|raw_log| L2ToL1Log::from_slice(&raw_log))
447-
.collect(),
448-
});
449-
450-
Ok(row)
451-
}
452-
453407
pub async fn set_dummy_inclusion_data_for_old_batches(
454408
&mut self,
455409
current_l2_da_validator: Address,

core/lib/merkle_tree/src/recovery/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ impl<DB: PruneDatabase, H: HashTree> MerkleTreeRecovery<DB, H> {
173173
%entries.key_range = entries_key_range(&entries),
174174
),
175175
)]
176+
#[allow(clippy::missing_errors_doc)]
176177
pub fn extend_linear(&mut self, entries: Vec<TreeEntry>) -> anyhow::Result<()> {
177178
tracing::debug!("Started extending tree");
178179
RECOVERY_METRICS.chunk_size.observe(entries.len());
@@ -200,6 +201,7 @@ impl<DB: PruneDatabase, H: HashTree> MerkleTreeRecovery<DB, H> {
200201
entries.len = entries.len(),
201202
),
202203
)]
204+
#[allow(clippy::missing_errors_doc)]
203205
pub fn extend_random(&mut self, entries: Vec<TreeEntry>) -> anyhow::Result<()> {
204206
tracing::debug!("Started extending tree");
205207
RECOVERY_METRICS.chunk_size.observe(entries.len());
@@ -223,7 +225,11 @@ impl<DB: PruneDatabase, H: HashTree> MerkleTreeRecovery<DB, H> {
223225
skip_all,
224226
fields(recovered_version = self.recovered_version),
225227
)]
226-
#[allow(clippy::missing_panics_doc, clippy::range_plus_one)]
228+
#[allow(
229+
clippy::missing_panics_doc,
230+
clippy::range_plus_one,
231+
clippy::missing_errors_doc
232+
)]
227233
pub fn finalize(mut self) -> anyhow::Result<DB> {
228234
let mut manifest = self.db.manifest().unwrap();
229235
// ^ `unwrap()` is safe: manifest is inserted into the DB on creation

core/lib/merkle_tree/src/repair.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ impl StaleKeysRepairTask {
9393

9494
/// Runs stale key detection for a single tree version.
9595
#[tracing::instrument(skip(db))]
96+
#[allow(clippy::missing_errors_doc, clippy::missing_panics_doc)]
9697
pub fn bogus_stale_keys(db: &RocksDBWrapper, version: u64) -> Vec<NodeKey> {
9798
const SAMPLE_COUNT: usize = 5;
9899

core/lib/state/src/storage_factory/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ impl CommonStorage<'static> {
161161
/// Creates a storage snapshot. Require protective reads to be persisted for the batch, otherwise
162162
/// will return `Ok(None)`.
163163
#[tracing::instrument(skip(connection))]
164+
#[allow(clippy::missing_errors_doc, clippy::missing_panics_doc)]
164165
pub async fn snapshot(
165166
connection: &mut Connection<'static, Core>,
166167
l1_batch_number: L1BatchNumber,

0 commit comments

Comments
 (0)