From 706907c34dc4f4397842b03598952653e4213b64 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Mon, 8 Jul 2024 12:59:11 +0100 Subject: [PATCH 01/15] BFT-474: Select unsigned batch numbers --- ...4960fc26d5ba2b8d0a5a5d1049d6346b9c073.json | 22 ++++++++++ core/lib/dal/src/consensus_dal.rs | 41 +++++++++++++++++++ core/node/consensus/src/storage/connection.rs | 16 ++++++++ core/node/consensus/src/storage/store.rs | 33 +++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 core/lib/dal/.sqlx/query-a73f453765b2f475c2f627b1a624960fc26d5ba2b8d0a5a5d1049d6346b9c073.json diff --git a/core/lib/dal/.sqlx/query-a73f453765b2f475c2f627b1a624960fc26d5ba2b8d0a5a5d1049d6346b9c073.json b/core/lib/dal/.sqlx/query-a73f453765b2f475c2f627b1a624960fc26d5ba2b8d0a5a5d1049d6346b9c073.json new file mode 100644 index 000000000000..6cb2db9d8652 --- /dev/null +++ b/core/lib/dal/.sqlx/query-a73f453765b2f475c2f627b1a624960fc26d5ba2b8d0a5a5d1049d6346b9c073.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n b.number\n FROM\n l1_batches b\n WHERE\n b.number >= $1\n AND NOT EXISTS (\n SELECT 1\n FROM l1_batches_consensus c\n WHERE c.l1_batch_number = b.number\n )\n ORDER BY \n b.number\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "a73f453765b2f475c2f627b1a624960fc26d5ba2b8d0a5a5d1049d6346b9c073" +} diff --git a/core/lib/dal/src/consensus_dal.rs b/core/lib/dal/src/consensus_dal.rs index 3efdf5ee577b..3895cd3a867f 100644 --- a/core/lib/dal/src/consensus_dal.rs +++ b/core/lib/dal/src/consensus_dal.rs @@ -480,6 +480,47 @@ impl ConsensusDal<'_, '_> { .number .map(|number| attester::BatchNumber(number as u64))) } + + /// Get the numbers of L1 batches which do not have a corresponding L1 quorum certificate + /// and need signatures to be gossiped and collected. + /// + /// On the main node this means every L1 batch, because we need QC over all of them to be + /// able to submit them to L1. Replicas don't necessarily have to have the QC, because once + /// the batch is on L1 and it's final, they can get the batch from there and don't need the + /// attestations. + pub async fn unsigned_batch_numbers( + &mut self, + min_batch_number: attester::BatchNumber, + ) -> DalResult> { + Ok(sqlx::query!( + r#" + SELECT + b.number + FROM + l1_batches b + WHERE + b.number >= $1 + AND NOT EXISTS ( + SELECT + 1 + FROM + l1_batches_consensus c + WHERE + c.l1_batch_number = b.number + ) + ORDER BY + b.number + "#, + min_batch_number.0 as i64 + ) + .instrument("unsigned_batch_numbers") + .report_latency() + .fetch_all(self.storage) + .await? + .into_iter() + .map(|row| attester::BatchNumber(row.number as u64)) + .collect()) + } } #[cfg(test)] diff --git a/core/node/consensus/src/storage/connection.rs b/core/node/consensus/src/storage/connection.rs index 1d8dfc3aed57..e10f7a824918 100644 --- a/core/node/consensus/src/storage/connection.rs +++ b/core/node/consensus/src/storage/connection.rs @@ -409,4 +409,20 @@ impl<'a> Connection<'a> { last, }) } + + /// Wrapper for `consensus_dal().unsigned_batch_numbers()`. + pub async fn unsigned_batch_numbers( + &mut self, + ctx: &ctx::Ctx, + min_batch_number: attester::BatchNumber, + ) -> ctx::Result> { + Ok(ctx + .wait( + self.0 + .consensus_dal() + .unsigned_batch_numbers(min_batch_number), + ) + .await? + .context("unsigned_batch_numbers()")?) + } } diff --git a/core/node/consensus/src/storage/store.rs b/core/node/consensus/src/storage/store.rs index c196989c300b..d2b051c59ab4 100644 --- a/core/node/consensus/src/storage/store.rs +++ b/core/node/consensus/src/storage/store.rs @@ -457,6 +457,28 @@ impl storage::PersistentBatchStore for Store { .1 } + /// Get the numbers of L1 batches which are missing the corresponding L1 batch quorum certificates + /// and potentially need to be signed by attesters. + async fn unsigned_batch_numbers( + &self, + ctx: &ctx::Ctx, + ) -> ctx::Result> { + // TODO: In the future external nodes will be able to ask the main node which L1 batch should be considered final. + // Later when we're fully decentralized the nodes will have to look at L1 instead. + // For now we make a best effort at gossiping votes, and have no way to tell what has been finalized, so we can + // just pick a reasonable maximum number of batches for which we might have to re-submit our signatures. + let Some(last_batch_number) = self.last_batch(ctx).await? else { + return Ok(Vec::new()); + }; + let min_batch_number = attester::BatchNumber(last_batch_number.0.saturating_sub(10)); + + self.conn(ctx) + .await? + .unsigned_batch_numbers(ctx, min_batch_number) + .await + .wrap("unsigned_batch_numbers") + } + /// Get the highest L1 batch number from storage. async fn last_batch(&self, ctx: &ctx::Ctx) -> ctx::Result> { self.conn(ctx) @@ -498,6 +520,17 @@ impl storage::PersistentBatchStore for Store { .wrap("get_batch") } + /// Returns the [attester::Batch] with the given number, which is the `message` that + /// appears in [attester::BatchQC], and represents the content that needs to be signed + /// by the attesters. + async fn get_batch_to_sign( + &self, + _ctx: &ctx::Ctx, + _number: attester::BatchNumber, + ) -> ctx::Result> { + todo!() + } + /// Returns the QC of the batch with the given number. async fn get_batch_qc( &self, From 7651fab2793c18aac5fc63ce6ebd089e1c19d9bf Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Mon, 8 Jul 2024 14:20:24 +0100 Subject: [PATCH 02/15] BFT-474: Test unsigned batches --- ...154165381937952e3edd0d9d23a6d5a31e7a.json} | 4 ++-- core/lib/dal/src/consensus_dal.rs | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) rename core/lib/dal/.sqlx/{query-a73f453765b2f475c2f627b1a624960fc26d5ba2b8d0a5a5d1049d6346b9c073.json => query-5b780fdc69905a9dd9c9acc25f59154165381937952e3edd0d9d23a6d5a31e7a.json} (55%) diff --git a/core/lib/dal/.sqlx/query-a73f453765b2f475c2f627b1a624960fc26d5ba2b8d0a5a5d1049d6346b9c073.json b/core/lib/dal/.sqlx/query-5b780fdc69905a9dd9c9acc25f59154165381937952e3edd0d9d23a6d5a31e7a.json similarity index 55% rename from core/lib/dal/.sqlx/query-a73f453765b2f475c2f627b1a624960fc26d5ba2b8d0a5a5d1049d6346b9c073.json rename to core/lib/dal/.sqlx/query-5b780fdc69905a9dd9c9acc25f59154165381937952e3edd0d9d23a6d5a31e7a.json index 6cb2db9d8652..e700f4337a29 100644 --- a/core/lib/dal/.sqlx/query-a73f453765b2f475c2f627b1a624960fc26d5ba2b8d0a5a5d1049d6346b9c073.json +++ b/core/lib/dal/.sqlx/query-5b780fdc69905a9dd9c9acc25f59154165381937952e3edd0d9d23a6d5a31e7a.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n b.number\n FROM\n l1_batches b\n WHERE\n b.number >= $1\n AND NOT EXISTS (\n SELECT 1\n FROM l1_batches_consensus c\n WHERE c.l1_batch_number = b.number\n )\n ORDER BY \n b.number\n ", + "query": "\n SELECT\n b.number\n FROM\n l1_batches b\n WHERE\n b.number >= $1\n AND NOT EXISTS (\n SELECT\n 1\n FROM\n l1_batches_consensus c\n WHERE\n c.l1_batch_number = b.number\n )\n ORDER BY\n b.number\n ", "describe": { "columns": [ { @@ -18,5 +18,5 @@ false ] }, - "hash": "a73f453765b2f475c2f627b1a624960fc26d5ba2b8d0a5a5d1049d6346b9c073" + "hash": "5b780fdc69905a9dd9c9acc25f59154165381937952e3edd0d9d23a6d5a31e7a" } diff --git a/core/lib/dal/src/consensus_dal.rs b/core/lib/dal/src/consensus_dal.rs index 3895cd3a867f..8ec2d9584ac4 100644 --- a/core/lib/dal/src/consensus_dal.rs +++ b/core/lib/dal/src/consensus_dal.rs @@ -653,5 +653,27 @@ mod tests { .insert_batch_certificate(&cert3) .await .expect_err("missing payload"); + + // Insert one more L1 batch without a certificate. + conn.blocks_dal() + .insert_mock_l1_batch(&create_l1_batch_header(batch_number + 1)) + .await + .unwrap(); + + // Check how many unsigned L1 batches we can find. + for (min_l1_batch_number, exp_num_unsigned) in [ + (0, 3), + (batch_number - 1, 3), + (batch_number, 2), + (batch_number + 1, 1), + (batch_number + 2, 0), + ] { + let unsigned = conn + .consensus_dal() + .unsigned_batch_numbers(attester::BatchNumber(min_l1_batch_number as u64)) + .await + .unwrap(); + assert_eq!(unsigned.len(), exp_num_unsigned); + } } } From 6b2d388e40a41653724fb93fe3767d86dbc249a6 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Mon, 8 Jul 2024 14:32:09 +0100 Subject: [PATCH 03/15] BFT-474: Impl get_batch_to_sign --- core/node/consensus/src/storage/store.rs | 29 ++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/core/node/consensus/src/storage/store.rs b/core/node/consensus/src/storage/store.rs index d2b051c59ab4..5721e543738b 100644 --- a/core/node/consensus/src/storage/store.rs +++ b/core/node/consensus/src/storage/store.rs @@ -3,11 +3,13 @@ use std::sync::Arc; use anyhow::Context as _; use zksync_concurrency::{ctx, error::Wrap as _, scope, sync, time}; use zksync_consensus_bft::PayloadManager; +use zksync_consensus_crypto::keccak256::Keccak256; use zksync_consensus_roles::{attester, validator}; use zksync_consensus_storage::{self as storage, BatchStoreState}; use zksync_dal::consensus_dal::{self, Payload}; +use zksync_l1_contract_interface::i_executor::structures::StoredBatchInfo; use zksync_node_sync::fetcher::{FetchedBlock, FetchedTransaction}; -use zksync_types::L2BlockNumber; +use zksync_types::{L1BatchNumber, L2BlockNumber}; use super::{Connection, PayloadQueue}; use crate::storage::{ConnectionPool, InsertCertificateError}; @@ -525,10 +527,29 @@ impl storage::PersistentBatchStore for Store { /// by the attesters. async fn get_batch_to_sign( &self, - _ctx: &ctx::Ctx, - _number: attester::BatchNumber, + ctx: &ctx::Ctx, + number: attester::BatchNumber, ) -> ctx::Result> { - todo!() + let Some(batch) = self + .conn(ctx) + .await? + .batch( + ctx, + L1BatchNumber(u32::try_from(number.0).context("number")?), + ) + .await + .wrap("batch")? + else { + return Ok(None); + }; + + let info = StoredBatchInfo::from(&batch); + let hash = Keccak256::from_bytes(info.hash().0); + + Ok(Some(attester::Batch { + number, + hash: attester::BatchHash(hash), + })) } /// Returns the QC of the batch with the given number. From 2e37721cc3faac76731b5ccc1fbf69272c6c7713 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Mon, 8 Jul 2024 14:52:42 +0100 Subject: [PATCH 04/15] BFT-474: Check hash in save cert --- core/lib/dal/src/consensus_dal.rs | 31 ++++--------------- core/node/consensus/src/storage/connection.rs | 21 +++++++++++++ 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/core/lib/dal/src/consensus_dal.rs b/core/lib/dal/src/consensus_dal.rs index 8ec2d9584ac4..337e46fd734e 100644 --- a/core/lib/dal/src/consensus_dal.rs +++ b/core/lib/dal/src/consensus_dal.rs @@ -7,7 +7,7 @@ use zksync_db_connection::{ error::{DalError, DalResult, SqlxContext}, instrument::{InstrumentExt, Instrumented}, }; -use zksync_types::{L1BatchNumber, L2BlockNumber}; +use zksync_types::L2BlockNumber; pub use crate::consensus::Payload; use crate::{Core, CoreDal}; @@ -409,29 +409,12 @@ impl ConsensusDal<'_, '_> { /// /// Insertion is allowed even if it creates gaps in the L1 batch history. /// - /// It fails if the batch payload is missing or it's not consistent with the QC. + /// This method assumes that all payload validation has been carried out by the caller. pub async fn insert_batch_certificate( &mut self, cert: &attester::BatchQC, ) -> Result<(), InsertCertificateError> { - use InsertCertificateError as E; - let mut txn = self.storage.start_transaction().await?; - - let l1_batch_number = L1BatchNumber(cert.message.number.0 as u32); - let _l1_batch_header = txn - .blocks_dal() - .get_l1_batch_header(l1_batch_number) - .await? - .ok_or(E::MissingPayload)?; - - // TODO: Verify that the certificate matches the stored batch: - // * add the hash of the batch to the `BatchQC` - // * find out which field in the `l1_batches` table contains the hash we need to match - // * ideally move the responsibility of validation outside this method - - // if header.payload != want_payload.encode().hash() { - // return Err(E::PayloadMismatch); - // } + let l1_batch_number = cert.message.number.0 as i64; let res = sqlx::query!( r#" @@ -441,20 +424,18 @@ impl ConsensusDal<'_, '_> { ($1, $2, NOW(), NOW()) ON CONFLICT (l1_batch_number) DO NOTHING "#, - i64::from(l1_batch_number.0), + l1_batch_number, zksync_protobuf::serde::serialize(cert, serde_json::value::Serializer).unwrap(), ) .instrument("insert_batch_certificate") .report_latency() - .execute(&mut txn) + .execute(self.storage) .await?; if res.rows_affected().is_zero() { - tracing::debug!(%l1_batch_number, "duplicate batch certificate"); + tracing::debug!(l1_batch_number, "duplicate batch certificate"); } - txn.commit().await.context("commit")?; - Ok(()) } diff --git a/core/node/consensus/src/storage/connection.rs b/core/node/consensus/src/storage/connection.rs index e10f7a824918..d0d68aa12076 100644 --- a/core/node/consensus/src/storage/connection.rs +++ b/core/node/consensus/src/storage/connection.rs @@ -3,6 +3,7 @@ use zksync_concurrency::{ctx, error::Wrap as _, time}; use zksync_consensus_roles::{attester, validator}; use zksync_consensus_storage::{self as storage, BatchStoreState}; use zksync_dal::{consensus_dal::Payload, Core, CoreDal, DalError}; +use zksync_l1_contract_interface::i_executor::structures::StoredBatchInfo; use zksync_node_sync::{fetcher::IoCursorExt as _, ActionQueueSender, SyncState}; use zksync_state_keeper::io::common::IoCursor; use zksync_types::{commitment::L1BatchWithMetadata, L1BatchNumber}; @@ -120,6 +121,26 @@ impl<'a> Connection<'a> { ctx: &ctx::Ctx, cert: &attester::BatchQC, ) -> Result<(), InsertCertificateError> { + use crate::storage::consensus_dal::InsertCertificateError as E; + + let l1_batch_number = L1BatchNumber(cert.message.number.0 as u32); + + let Some(l1_batch) = self + .0 + .blocks_dal() + .get_l1_batch_metadata(l1_batch_number) + .await + .map_err(E::Dal)? + else { + return Err(E::MissingPayload.into()); + }; + + let l1_batch_info = StoredBatchInfo::from(&l1_batch); + + if l1_batch_info.hash().0 != *cert.message.hash.0.as_bytes() { + return Err(E::PayloadMismatch.into()); + } + Ok(ctx .wait(self.0.consensus_dal().insert_batch_certificate(cert)) .await??) From 58c5069f7b2c4616e3d0852c0889dae091ba2fa8 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Mon, 8 Jul 2024 16:30:24 +0100 Subject: [PATCH 05/15] BFT-474: Fix the test --- core/lib/dal/src/consensus_dal.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/core/lib/dal/src/consensus_dal.rs b/core/lib/dal/src/consensus_dal.rs index 337e46fd734e..f1beba6eed51 100644 --- a/core/lib/dal/src/consensus_dal.rs +++ b/core/lib/dal/src/consensus_dal.rs @@ -573,7 +573,8 @@ mod tests { // Insert some mock L2 blocks and L1 batches let mut block_number = 0; let mut batch_number = 0; - for _ in 0..3 { + let num_batches = 3; + for _ in 0..num_batches { for _ in 0..3 { block_number += 1; let l2_block = create_l2_block_header(block_number); @@ -641,20 +642,25 @@ mod tests { .await .unwrap(); + let num_batches = num_batches + 1; + let num_unsigned = num_batches - 1; + // Check how many unsigned L1 batches we can find. - for (min_l1_batch_number, exp_num_unsigned) in [ - (0, 3), - (batch_number - 1, 3), - (batch_number, 2), - (batch_number + 1, 1), - (batch_number + 2, 0), - ] { + for (i, (min_l1_batch_number, exp_num_unsigned)) in [ + (0, num_unsigned), + (batch_number, 1), // This one has the corresponding cert + (batch_number + 1, 1), // This is the one we inserted later + (batch_number + 2, 0), // Querying beyond the last one + ] + .into_iter() + .enumerate() + { let unsigned = conn .consensus_dal() - .unsigned_batch_numbers(attester::BatchNumber(min_l1_batch_number as u64)) + .unsigned_batch_numbers(attester::BatchNumber(u64::from(min_l1_batch_number))) .await .unwrap(); - assert_eq!(unsigned.len(), exp_num_unsigned); + assert_eq!(unsigned.len(), exp_num_unsigned, "test case {i}"); } } } From 512a7899390457f9c427d3d55c429de6d15f6e8b Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Tue, 9 Jul 2024 16:13:18 +0100 Subject: [PATCH 06/15] TEMP: Patch Cargo.toml to point at the era-consensus repo --- Cargo.lock | 31 +++++++++++-------------------- Cargo.toml | 12 ++++++++++++ 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 750f64f794af..5ed00a2884a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8092,8 +8092,7 @@ dependencies = [ [[package]] name = "zksync_concurrency" version = "0.1.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28279a743cd2ec5a0e3f0fec31b2e4fdd509d0b513e0aaeb000200ce464123e5" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" dependencies = [ "anyhow", "once_cell", @@ -8125,8 +8124,7 @@ dependencies = [ [[package]] name = "zksync_consensus_bft" version = "0.1.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "011210cdeb207516fe95ec2c8a77b3c36e444e2cd17e7db57afdc55a263025d6" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" dependencies = [ "anyhow", "async-trait", @@ -8147,8 +8145,7 @@ dependencies = [ [[package]] name = "zksync_consensus_crypto" version = "0.1.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dbbc36ff78548f022192f20fb76909b1b0a460fc85289ccc54ce0ce54263165" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" dependencies = [ "anyhow", "blst", @@ -8171,8 +8168,7 @@ dependencies = [ [[package]] name = "zksync_consensus_executor" version = "0.1.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f6811105b9b0fffb5983382c504d466a415f41f4a3b0f6743837bcbfc0b332" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" dependencies = [ "anyhow", "rand 0.8.5", @@ -8191,8 +8187,7 @@ dependencies = [ [[package]] name = "zksync_consensus_network" version = "0.1.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79538ef206af7006c94c8d047582cf214ac493f7dd8340d40cace4f248d8c35" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" dependencies = [ "anyhow", "async-trait", @@ -8226,8 +8221,7 @@ dependencies = [ [[package]] name = "zksync_consensus_roles" version = "0.1.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0070c54eed2f5cf26e76d9ec3ccdf05fdafb18c0712c8d97ef4987634972396" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" dependencies = [ "anyhow", "bit-vec", @@ -8248,8 +8242,7 @@ dependencies = [ [[package]] name = "zksync_consensus_storage" version = "0.1.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d221fbd8e22f49175132c252a4923a945c1fa4a548ad66c3fc0366789cc9e53" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" dependencies = [ "anyhow", "async-trait", @@ -8259,6 +8252,7 @@ dependencies = [ "tracing", "vise", "zksync_concurrency", + "zksync_consensus_crypto", "zksync_consensus_roles", "zksync_protobuf", "zksync_protobuf_build", @@ -8267,8 +8261,7 @@ dependencies = [ [[package]] name = "zksync_consensus_utils" version = "0.1.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c3d9b3b6b795ce16e0ead2b8813a2f7a1a01c9a9e3fb50993d6ecbfcdbca98" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" dependencies = [ "anyhow", "rand 0.8.5", @@ -9202,8 +9195,7 @@ dependencies = [ [[package]] name = "zksync_protobuf" version = "0.1.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe77d262206bb22f4bc26e75b68466b2e7043baa4963fe97190ce8540a5d700" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" dependencies = [ "anyhow", "bit-vec", @@ -9223,8 +9215,7 @@ dependencies = [ [[package]] name = "zksync_protobuf_build" version = "0.1.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1205d607aa7291e3e016ce202d97cd7eb7d232913076dd873cbe48d564bf656" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" dependencies = [ "anyhow", "heck 0.5.0", diff --git a/Cargo.toml b/Cargo.toml index 443f85493865..9215b3bc34b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -284,3 +284,15 @@ zksync_contract_verification_server = { path = "core/node/contract_verification_ zksync_node_api_server = { path = "core/node/api_server" } zksync_tee_verifier_input_producer = { path = "core/node/tee_verifier_input_producer" } zksync_base_token_adjuster = { path = "core/node/base_token_adjuster" } + +[patch.crates-io] +zksync_concurrency = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } +zksync_consensus_bft = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } +zksync_consensus_crypto = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } +zksync_consensus_executor = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } +zksync_consensus_network = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } +zksync_consensus_roles = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } +zksync_consensus_storage = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } +zksync_consensus_utils = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } +zksync_protobuf = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } +zksync_protobuf_build = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } From ed0e867a17920592fb11e919b4e9a49a389e3c76 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Tue, 9 Jul 2024 17:25:28 +0100 Subject: [PATCH 07/15] BFT-474: Fix comment --- core/node/consensus/src/storage/connection.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/node/consensus/src/storage/connection.rs b/core/node/consensus/src/storage/connection.rs index d0d68aa12076..2bb6a5c674fb 100644 --- a/core/node/consensus/src/storage/connection.rs +++ b/core/node/consensus/src/storage/connection.rs @@ -365,8 +365,8 @@ impl<'a> Connection<'a> { // TODO: Fill out the proof when we have the stateless L1 batch validation story finished. // It is supposed to be a Merkle proof that the rolling hash of the batch has been included - // in the L1 state tree. The state root hash of L1 won't be available in the DB, it requires - // an API client. + // in the L1 system contract state tree. It is *not* the Ethereum state root hash, so producing + // it can be done without an L1 client, which is only required for validation. let batch = attester::SyncBatch { number, payloads, From 2c831cbb149f496c61ece60fbfff5322a30100b6 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Tue, 9 Jul 2024 12:53:08 +0100 Subject: [PATCH 08/15] BFT-474: Replace unsigned_batch_numbers with earliest_batch_number_to_sign --- ...9154165381937952e3edd0d9d23a6d5a31e7a.json | 22 ------- ...a2f2d19eead58df0eca9f985027aca7350530.json | 22 +++++++ core/lib/dal/src/consensus_dal.rs | 59 ++++++++----------- core/node/consensus/src/storage/connection.rs | 10 ++-- core/node/consensus/src/storage/store.rs | 14 ++--- 5 files changed, 59 insertions(+), 68 deletions(-) delete mode 100644 core/lib/dal/.sqlx/query-5b780fdc69905a9dd9c9acc25f59154165381937952e3edd0d9d23a6d5a31e7a.json create mode 100644 core/lib/dal/.sqlx/query-d38d07f12619081a9123080c063a2f2d19eead58df0eca9f985027aca7350530.json diff --git a/core/lib/dal/.sqlx/query-5b780fdc69905a9dd9c9acc25f59154165381937952e3edd0d9d23a6d5a31e7a.json b/core/lib/dal/.sqlx/query-5b780fdc69905a9dd9c9acc25f59154165381937952e3edd0d9d23a6d5a31e7a.json deleted file mode 100644 index e700f4337a29..000000000000 --- a/core/lib/dal/.sqlx/query-5b780fdc69905a9dd9c9acc25f59154165381937952e3edd0d9d23a6d5a31e7a.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT\n b.number\n FROM\n l1_batches b\n WHERE\n b.number >= $1\n AND NOT EXISTS (\n SELECT\n 1\n FROM\n l1_batches_consensus c\n WHERE\n c.l1_batch_number = b.number\n )\n ORDER BY\n b.number\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "number", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - false - ] - }, - "hash": "5b780fdc69905a9dd9c9acc25f59154165381937952e3edd0d9d23a6d5a31e7a" -} diff --git a/core/lib/dal/.sqlx/query-d38d07f12619081a9123080c063a2f2d19eead58df0eca9f985027aca7350530.json b/core/lib/dal/.sqlx/query-d38d07f12619081a9123080c063a2f2d19eead58df0eca9f985027aca7350530.json new file mode 100644 index 000000000000..8e80801b24c3 --- /dev/null +++ b/core/lib/dal/.sqlx/query-d38d07f12619081a9123080c063a2f2d19eead58df0eca9f985027aca7350530.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n MIN(b.number) AS \"number\"\n FROM\n l1_batches b\n LEFT JOIN l1_batches_consensus c ON b.number = c.l1_batch_number\n WHERE\n b.number >= $1\n AND c.l1_batch_number IS NULL\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "number", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + null + ] + }, + "hash": "d38d07f12619081a9123080c063a2f2d19eead58df0eca9f985027aca7350530" +} diff --git a/core/lib/dal/src/consensus_dal.rs b/core/lib/dal/src/consensus_dal.rs index f1beba6eed51..5a3e8a05d662 100644 --- a/core/lib/dal/src/consensus_dal.rs +++ b/core/lib/dal/src/consensus_dal.rs @@ -462,45 +462,38 @@ impl ConsensusDal<'_, '_> { .map(|number| attester::BatchNumber(number as u64))) } - /// Get the numbers of L1 batches which do not have a corresponding L1 quorum certificate + /// Get the earliest of L1 batch which does not have a corresponding quorum certificate /// and need signatures to be gossiped and collected. /// /// On the main node this means every L1 batch, because we need QC over all of them to be /// able to submit them to L1. Replicas don't necessarily have to have the QC, because once /// the batch is on L1 and it's final, they can get the batch from there and don't need the - /// attestations. - pub async fn unsigned_batch_numbers( + /// attestations. The caller will have to choose the `min_batch_number` accordingly. + pub async fn earliest_batch_number_to_sign( &mut self, min_batch_number: attester::BatchNumber, - ) -> DalResult> { - Ok(sqlx::query!( + ) -> DalResult> { + let row = sqlx::query!( r#" SELECT - b.number + MIN(b.number) AS "number" FROM l1_batches b + LEFT JOIN l1_batches_consensus c ON b.number = c.l1_batch_number WHERE b.number >= $1 - AND NOT EXISTS ( - SELECT - 1 - FROM - l1_batches_consensus c - WHERE - c.l1_batch_number = b.number - ) - ORDER BY - b.number + AND c.l1_batch_number IS NULL "#, min_batch_number.0 as i64 ) - .instrument("unsigned_batch_numbers") + .instrument("earliest_batch_number_to_sign") .report_latency() - .fetch_all(self.storage) - .await? - .into_iter() - .map(|row| attester::BatchNumber(row.number as u64)) - .collect()) + .fetch_one(self.storage) + .await?; + + Ok(row + .number + .map(|number| attester::BatchNumber(number as u64))) } } @@ -642,25 +635,23 @@ mod tests { .await .unwrap(); - let num_batches = num_batches + 1; - let num_unsigned = num_batches - 1; - - // Check how many unsigned L1 batches we can find. - for (i, (min_l1_batch_number, exp_num_unsigned)) in [ - (0, num_unsigned), - (batch_number, 1), // This one has the corresponding cert - (batch_number + 1, 1), // This is the one we inserted later - (batch_number + 2, 0), // Querying beyond the last one + // Check the earliest batch number to be signed at various points. + for (i, (min_l1_batch_number, want_earliest)) in [ + (0, Some(batch_number - 2)), // We inserted 2 unsigned batches before the first cert + (batch_number, Some(batch_number + 1)), // This one has the corresponding cert + (batch_number + 1, Some(batch_number + 1)), // This is the one we inserted later without a cert + (batch_number + 2, None), // Querying beyond the last one ] .into_iter() .enumerate() { - let unsigned = conn + let min_batch_number = attester::BatchNumber(u64::from(min_l1_batch_number)); + let earliest = conn .consensus_dal() - .unsigned_batch_numbers(attester::BatchNumber(u64::from(min_l1_batch_number))) + .earliest_batch_number_to_sign(min_batch_number) .await .unwrap(); - assert_eq!(unsigned.len(), exp_num_unsigned, "test case {i}"); + assert_eq!(earliest.map(|n| n.0 as u32), want_earliest, "test case {i}"); } } } diff --git a/core/node/consensus/src/storage/connection.rs b/core/node/consensus/src/storage/connection.rs index 2bb6a5c674fb..e73125da5873 100644 --- a/core/node/consensus/src/storage/connection.rs +++ b/core/node/consensus/src/storage/connection.rs @@ -431,19 +431,19 @@ impl<'a> Connection<'a> { }) } - /// Wrapper for `consensus_dal().unsigned_batch_numbers()`. - pub async fn unsigned_batch_numbers( + /// Wrapper for `consensus_dal().earliest_batch_number_to_sign()`. + pub async fn earliest_batch_number_to_sign( &mut self, ctx: &ctx::Ctx, min_batch_number: attester::BatchNumber, - ) -> ctx::Result> { + ) -> ctx::Result> { Ok(ctx .wait( self.0 .consensus_dal() - .unsigned_batch_numbers(min_batch_number), + .earliest_batch_number_to_sign(min_batch_number), ) .await? - .context("unsigned_batch_numbers()")?) + .context("earliest_batch_number_to_sign()")?) } } diff --git a/core/node/consensus/src/storage/store.rs b/core/node/consensus/src/storage/store.rs index 5721e543738b..dc4e3165cd60 100644 --- a/core/node/consensus/src/storage/store.rs +++ b/core/node/consensus/src/storage/store.rs @@ -459,26 +459,26 @@ impl storage::PersistentBatchStore for Store { .1 } - /// Get the numbers of L1 batches which are missing the corresponding L1 batch quorum certificates - /// and potentially need to be signed by attesters. - async fn unsigned_batch_numbers( + /// Get the earliest L1 batche for which there is no corresponding L1 batch quorum certificate, + /// and thus it potentially needs to be signed by attesters. + async fn earliest_batch_number_to_sign( &self, ctx: &ctx::Ctx, - ) -> ctx::Result> { + ) -> ctx::Result> { // TODO: In the future external nodes will be able to ask the main node which L1 batch should be considered final. // Later when we're fully decentralized the nodes will have to look at L1 instead. // For now we make a best effort at gossiping votes, and have no way to tell what has been finalized, so we can // just pick a reasonable maximum number of batches for which we might have to re-submit our signatures. let Some(last_batch_number) = self.last_batch(ctx).await? else { - return Ok(Vec::new()); + return Ok(None); }; let min_batch_number = attester::BatchNumber(last_batch_number.0.saturating_sub(10)); self.conn(ctx) .await? - .unsigned_batch_numbers(ctx, min_batch_number) + .earliest_batch_number_to_sign(ctx, min_batch_number) .await - .wrap("unsigned_batch_numbers") + .wrap("earliest_batch_number_to_sign") } /// Get the highest L1 batch number from storage. From 92dd25f6a50c8cbfe3fd901c05566c0b2847929c Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Tue, 9 Jul 2024 16:44:17 +0100 Subject: [PATCH 09/15] TEMP: Patch Cargo.toml to point at the era-consensus repo --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 20 ++++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a62f541fb69..5d6cf7d8a9d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8109,7 +8109,7 @@ dependencies = [ [[package]] name = "zksync_concurrency" version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" dependencies = [ "anyhow", "once_cell", @@ -8142,7 +8142,7 @@ dependencies = [ [[package]] name = "zksync_consensus_bft" version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" dependencies = [ "anyhow", "async-trait", @@ -8163,7 +8163,7 @@ dependencies = [ [[package]] name = "zksync_consensus_crypto" version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" dependencies = [ "anyhow", "blst", @@ -8186,7 +8186,7 @@ dependencies = [ [[package]] name = "zksync_consensus_executor" version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" dependencies = [ "anyhow", "rand 0.8.5", @@ -8205,7 +8205,7 @@ dependencies = [ [[package]] name = "zksync_consensus_network" version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" dependencies = [ "anyhow", "async-trait", @@ -8239,7 +8239,7 @@ dependencies = [ [[package]] name = "zksync_consensus_roles" version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" dependencies = [ "anyhow", "bit-vec", @@ -8260,7 +8260,7 @@ dependencies = [ [[package]] name = "zksync_consensus_storage" version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" dependencies = [ "anyhow", "async-trait", @@ -8279,7 +8279,7 @@ dependencies = [ [[package]] name = "zksync_consensus_utils" version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" dependencies = [ "anyhow", "rand 0.8.5", @@ -9222,7 +9222,7 @@ dependencies = [ [[package]] name = "zksync_protobuf" version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" dependencies = [ "anyhow", "bit-vec", @@ -9242,7 +9242,7 @@ dependencies = [ [[package]] name = "zksync_protobuf_build" version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=78ade978b38480cab2b4335d9f41155e24d5c9a1#78ade978b38480cab2b4335d9f41155e24d5c9a1" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" dependencies = [ "anyhow", "heck 0.5.0", diff --git a/Cargo.toml b/Cargo.toml index b77a046331d0..6ecb3bd8b362 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -287,13 +287,13 @@ zksync_tee_verifier_input_producer = { path = "core/node/tee_verifier_input_prod zksync_base_token_adjuster = { path = "core/node/base_token_adjuster" } [patch.crates-io] -zksync_concurrency = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } -zksync_consensus_bft = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } -zksync_consensus_crypto = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } -zksync_consensus_executor = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } -zksync_consensus_network = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } -zksync_consensus_roles = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } -zksync_consensus_storage = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } -zksync_consensus_utils = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } -zksync_protobuf = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } -zksync_protobuf_build = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "78ade978b38480cab2b4335d9f41155e24d5c9a1" } +zksync_concurrency = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } +zksync_consensus_bft = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } +zksync_consensus_crypto = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } +zksync_consensus_executor = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } +zksync_consensus_network = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } +zksync_consensus_roles = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } +zksync_consensus_storage = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } +zksync_consensus_utils = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } +zksync_protobuf = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } +zksync_protobuf_build = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } From 673047f3fc5970637fba32d991756380f775771e Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Tue, 9 Jul 2024 16:44:47 +0100 Subject: [PATCH 10/15] BFT-474: Add max_batch_size --- core/lib/config/src/configs/consensus.rs | 7 ++++++ core/lib/config/src/testonly.rs | 1 + core/lib/protobuf_config/src/consensus.rs | 23 +++++++++++++++---- .../src/proto/core/consensus.proto | 3 +++ core/node/consensus/src/config.rs | 1 + core/node/consensus/src/testonly.rs | 1 + 6 files changed, 32 insertions(+), 4 deletions(-) diff --git a/core/lib/config/src/configs/consensus.rs b/core/lib/config/src/configs/consensus.rs index ec4edd486ac0..50885a6ec6fe 100644 --- a/core/lib/config/src/configs/consensus.rs +++ b/core/lib/config/src/configs/consensus.rs @@ -120,6 +120,13 @@ pub struct ConsensusConfig { /// Maximal allowed size of the payload in bytes. pub max_payload_size: usize, + /// Maximal allowed size of the sync-batch payloads in bytes. + /// + /// The batch consists of block payloads and a Merkle proof of inclusion on L1 (~1kB), + /// so the maximum batch size should be the maximum payload size times the maximum number + /// of blocks in a batch. + pub max_batch_size: usize, + /// Limit on the number of inbound connections outside /// of the `static_inbound` set. pub gossip_dynamic_inbound_limit: usize, diff --git a/core/lib/config/src/testonly.rs b/core/lib/config/src/testonly.rs index c41180fe42b3..b9a78676697e 100644 --- a/core/lib/config/src/testonly.rs +++ b/core/lib/config/src/testonly.rs @@ -755,6 +755,7 @@ impl Distribution for EncodeDist { server_addr: self.sample(rng), public_addr: Host(self.sample(rng)), max_payload_size: self.sample(rng), + max_batch_size: self.sample(rng), gossip_dynamic_inbound_limit: self.sample(rng), gossip_static_inbound: self .sample_range(rng) diff --git a/core/lib/protobuf_config/src/consensus.rs b/core/lib/protobuf_config/src/consensus.rs index c04120edcc54..fb3954d20e5d 100644 --- a/core/lib/protobuf_config/src/consensus.rs +++ b/core/lib/protobuf_config/src/consensus.rs @@ -4,7 +4,7 @@ use zksync_config::configs::consensus::{ AttesterPublicKey, ConsensusConfig, GenesisSpec, Host, NodePublicKey, ProtocolVersion, RpcConfig, ValidatorPublicKey, WeightedAttester, WeightedValidator, }; -use zksync_protobuf::{read_optional, repr::ProtoRepr, required, ProtoFmt}; +use zksync_protobuf::{kB, read_optional, repr::ProtoRepr, required, ProtoFmt}; use crate::{proto::consensus as proto, read_optional_repr}; @@ -100,14 +100,28 @@ impl ProtoRepr for proto::Config { let addr = Host(required(&e.addr).context("addr")?.clone()); anyhow::Ok((key, addr)) }; + + let max_payload_size = required(&self.max_payload_size) + .and_then(|x| Ok((*x).try_into()?)) + .context("max_payload_size")?; + + let max_batch_size = match self.max_batch_size { + Some(x) => x.try_into().context("max_batch_size")?, + None => { + // Compute a default batch size: the batch interval is ~1 minute, + // so there will be ~60 blocks, and an Ethereum Merkle proof is ~1kB. + // Using 100 to be generous. + max_payload_size * 100 + kB + } + }; + Ok(Self::Type { server_addr: required(&self.server_addr) .and_then(|x| Ok(x.parse()?)) .context("server_addr")?, public_addr: Host(required(&self.public_addr).context("public_addr")?.clone()), - max_payload_size: required(&self.max_payload_size) - .and_then(|x| Ok((*x).try_into()?)) - .context("max_payload_size")?, + max_payload_size, + max_batch_size, gossip_dynamic_inbound_limit: required(&self.gossip_dynamic_inbound_limit) .and_then(|x| Ok((*x).try_into()?)) .context("gossip_dynamic_inbound_limit")?, @@ -132,6 +146,7 @@ impl ProtoRepr for proto::Config { server_addr: Some(this.server_addr.to_string()), public_addr: Some(this.public_addr.0.clone()), max_payload_size: Some(this.max_payload_size.try_into().unwrap()), + max_batch_size: Some(this.max_batch_size.try_into().unwrap()), gossip_dynamic_inbound_limit: Some( this.gossip_dynamic_inbound_limit.try_into().unwrap(), ), diff --git a/core/lib/protobuf_config/src/proto/core/consensus.proto b/core/lib/protobuf_config/src/proto/core/consensus.proto index 2adc70886e9e..c64c993be7c8 100644 --- a/core/lib/protobuf_config/src/proto/core/consensus.proto +++ b/core/lib/protobuf_config/src/proto/core/consensus.proto @@ -78,6 +78,9 @@ message Config { // Maximal allowed size of the payload. optional uint64 max_payload_size = 4; // required; bytes + // Maximal allowed size of the sync batches. + optional uint64 max_batch_size = 10; // required; bytes + // Inbound connections that should be unconditionally accepted on the gossip network. repeated string gossip_static_inbound = 5; // required; NodePublicKey diff --git a/core/node/consensus/src/config.rs b/core/node/consensus/src/config.rs index 75e329d6c347..f2ca16956a2d 100644 --- a/core/node/consensus/src/config.rs +++ b/core/node/consensus/src/config.rs @@ -126,6 +126,7 @@ pub(super) fn executor( server_addr: cfg.server_addr, public_addr: net::Host(cfg.public_addr.0.clone()), max_payload_size: cfg.max_payload_size, + max_batch_size: cfg.max_batch_size, node_key: node_key(secrets) .context("node_key")? .context("missing node_key")?, diff --git a/core/node/consensus/src/testonly.rs b/core/node/consensus/src/testonly.rs index 7ca518a183a7..922b53f11f8d 100644 --- a/core/node/consensus/src/testonly.rs +++ b/core/node/consensus/src/testonly.rs @@ -79,6 +79,7 @@ pub(super) fn config(cfg: &network::Config) -> (config::ConsensusConfig, config: server_addr: *cfg.server_addr, public_addr: config::Host(cfg.public_addr.0.clone()), max_payload_size: usize::MAX, + max_batch_size: usize::MAX, gossip_dynamic_inbound_limit: cfg.gossip.dynamic_inbound_limit, gossip_static_inbound: cfg .gossip From e584719567e364a21041c2537684577d9c1f7776 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Tue, 9 Jul 2024 16:46:28 +0100 Subject: [PATCH 11/15] BFT-474: Re-enable persisted() --- core/node/consensus/src/storage/store.rs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/core/node/consensus/src/storage/store.rs b/core/node/consensus/src/storage/store.rs index dc4e3165cd60..9f00590fe53f 100644 --- a/core/node/consensus/src/storage/store.rs +++ b/core/node/consensus/src/storage/store.rs @@ -443,20 +443,7 @@ impl PayloadManager for Store { impl storage::PersistentBatchStore for Store { /// Range of batches persisted in storage. fn persisted(&self) -> sync::watch::Receiver { - // Normally we'd return this, but it causes the following test to run forever: - // RUST_LOG=info zk test rust test_full_nodes --no-capture - // - // The error seems to be related to the size of messages, although I'm not sure - // why it retries it forever. Since the gossip of SyncBatch is not fully functional - // yet, for now let's just return a fake response that never changes, which should - // disable gossiping on honest nodes. - let _ = self.batches_persisted.clone(); - - sync::watch::channel(storage::BatchStoreState { - first: attester::BatchNumber(0), - last: None, - }) - .1 + self.batches_persisted.clone() } /// Get the earliest L1 batche for which there is no corresponding L1 batch quorum certificate, From 30a54beb3790c3011dbe9484e8336c5990d44bf4 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Tue, 9 Jul 2024 20:39:36 +0100 Subject: [PATCH 12/15] BFT-474: Build against rc.2 --- Cargo.lock | 50 ++++++++++++++++++++++++++----------------- Cargo.toml | 32 +++++++++------------------ prover/Cargo.lock | 29 +++++++++++++------------ zk_toolbox/Cargo.lock | 16 +++++++------- 4 files changed, 63 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d6cf7d8a9d5..c7c2191377af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8108,8 +8108,9 @@ dependencies = [ [[package]] name = "zksync_concurrency" -version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" +version = "0.1.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1af85d9a31c534a29877c88474cf5f1c46ad25f7c48efff61ea40f4aa83c5459" dependencies = [ "anyhow", "once_cell", @@ -8141,8 +8142,9 @@ dependencies = [ [[package]] name = "zksync_consensus_bft" -version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" +version = "0.1.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddbee11ed4fafe461092fb73d3879325f08243fe50351baab6b5f593fee88f06" dependencies = [ "anyhow", "async-trait", @@ -8162,8 +8164,9 @@ dependencies = [ [[package]] name = "zksync_consensus_crypto" -version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" +version = "0.1.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b3867f9b4778616d87f157d1049e47290a3bca5ec9db208164f8902524ae92c" dependencies = [ "anyhow", "blst", @@ -8185,8 +8188,9 @@ dependencies = [ [[package]] name = "zksync_consensus_executor" -version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" +version = "0.1.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7d50aa34616a9c1f4cdc7c47aae2df61474e137e41125c9d5fbfc1e5a1faaa" dependencies = [ "anyhow", "rand 0.8.5", @@ -8204,8 +8208,9 @@ dependencies = [ [[package]] name = "zksync_consensus_network" -version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" +version = "0.1.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced7deafe460c74321edf79486980f9f75da121a1e52e5805392946dabafdf82" dependencies = [ "anyhow", "async-trait", @@ -8238,8 +8243,9 @@ dependencies = [ [[package]] name = "zksync_consensus_roles" -version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" +version = "0.1.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55dacdf1bad5d9efe7dd9db200421afa0c3bf5cfc7fdce4a64720a5dd0685807" dependencies = [ "anyhow", "bit-vec", @@ -8259,8 +8265,9 @@ dependencies = [ [[package]] name = "zksync_consensus_storage" -version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" +version = "0.1.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f796020459775391094b9dcd133f01b5127059fe167cf412b2d1aed23fe0e52f" dependencies = [ "anyhow", "async-trait", @@ -8278,8 +8285,9 @@ dependencies = [ [[package]] name = "zksync_consensus_utils" -version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" +version = "0.1.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "587de103f745d0b88b49a9fb98cb002c4b7ce6ad042e17845091dce67b8aa984" dependencies = [ "anyhow", "rand 0.8.5", @@ -9221,8 +9229,9 @@ dependencies = [ [[package]] name = "zksync_protobuf" -version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" +version = "0.1.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86baa84d8bbbbeea269c0f99aca88364e4fd2a08e6ae7051ff87317132b4ef9" dependencies = [ "anyhow", "bit-vec", @@ -9241,8 +9250,9 @@ dependencies = [ [[package]] name = "zksync_protobuf_build" -version = "0.1.0-rc.1" -source = "git+https://github.com/matter-labs/era-consensus.git?rev=ed5832d90c3c202dcb28ebcd87926eac51f961d2#ed5832d90c3c202dcb28ebcd87926eac51f961d2" +version = "0.1.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f221ce83f4622c3d8732d09f4461d116d7b10f1cc9d1d1cd014c1fa836c168e6" dependencies = [ "anyhow", "heck 0.5.0", diff --git a/Cargo.toml b/Cargo.toml index 6ecb3bd8b362..6fe4b0e442ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -206,16 +206,16 @@ zk_evm_1_4_1 = { package = "zk_evm", version = "0.141.0" } zk_evm_1_5_0 = { package = "zk_evm", version = "0.150.0" } # Consensus dependencies. -zksync_concurrency = "=0.1.0-rc.1" -zksync_consensus_bft = "=0.1.0-rc.1" -zksync_consensus_crypto = "=0.1.0-rc.1" -zksync_consensus_executor = "=0.1.0-rc.1" -zksync_consensus_network = "=0.1.0-rc.1" -zksync_consensus_roles = "=0.1.0-rc.1" -zksync_consensus_storage = "=0.1.0-rc.1" -zksync_consensus_utils = "=0.1.0-rc.1" -zksync_protobuf = "=0.1.0-rc.1" -zksync_protobuf_build = "=0.1.0-rc.1" +zksync_concurrency = "=0.1.0-rc.2" +zksync_consensus_bft = "=0.1.0-rc.2" +zksync_consensus_crypto = "=0.1.0-rc.2" +zksync_consensus_executor = "=0.1.0-rc.2" +zksync_consensus_network = "=0.1.0-rc.2" +zksync_consensus_roles = "=0.1.0-rc.2" +zksync_consensus_storage = "=0.1.0-rc.2" +zksync_consensus_utils = "=0.1.0-rc.2" +zksync_protobuf = "=0.1.0-rc.2" +zksync_protobuf_build = "=0.1.0-rc.2" # "Local" dependencies zksync_multivm = { path = "core/lib/multivm" } @@ -285,15 +285,3 @@ zksync_contract_verification_server = { path = "core/node/contract_verification_ zksync_node_api_server = { path = "core/node/api_server" } zksync_tee_verifier_input_producer = { path = "core/node/tee_verifier_input_producer" } zksync_base_token_adjuster = { path = "core/node/base_token_adjuster" } - -[patch.crates-io] -zksync_concurrency = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } -zksync_consensus_bft = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } -zksync_consensus_crypto = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } -zksync_consensus_executor = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } -zksync_consensus_network = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } -zksync_consensus_roles = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } -zksync_consensus_storage = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } -zksync_consensus_utils = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } -zksync_protobuf = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } -zksync_protobuf_build = { version = "0.1.0-rc.1", git = "https://github.com/matter-labs/era-consensus.git", rev = "ed5832d90c3c202dcb28ebcd87926eac51f961d2" } diff --git a/prover/Cargo.lock b/prover/Cargo.lock index c186516cf3cc..a1bf690eb9a9 100644 --- a/prover/Cargo.lock +++ b/prover/Cargo.lock @@ -7716,9 +7716,9 @@ dependencies = [ [[package]] name = "zksync_concurrency" -version = "0.1.0-rc.1" +version = "0.1.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28279a743cd2ec5a0e3f0fec31b2e4fdd509d0b513e0aaeb000200ce464123e5" +checksum = "1af85d9a31c534a29877c88474cf5f1c46ad25f7c48efff61ea40f4aa83c5459" dependencies = [ "anyhow", "once_cell", @@ -7750,9 +7750,9 @@ dependencies = [ [[package]] name = "zksync_consensus_crypto" -version = "0.1.0-rc.1" +version = "0.1.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dbbc36ff78548f022192f20fb76909b1b0a460fc85289ccc54ce0ce54263165" +checksum = "7b3867f9b4778616d87f157d1049e47290a3bca5ec9db208164f8902524ae92c" dependencies = [ "anyhow", "blst", @@ -7774,9 +7774,9 @@ dependencies = [ [[package]] name = "zksync_consensus_roles" -version = "0.1.0-rc.1" +version = "0.1.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0070c54eed2f5cf26e76d9ec3ccdf05fdafb18c0712c8d97ef4987634972396" +checksum = "55dacdf1bad5d9efe7dd9db200421afa0c3bf5cfc7fdce4a64720a5dd0685807" dependencies = [ "anyhow", "bit-vec", @@ -7796,9 +7796,9 @@ dependencies = [ [[package]] name = "zksync_consensus_storage" -version = "0.1.0-rc.1" +version = "0.1.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d221fbd8e22f49175132c252a4923a945c1fa4a548ad66c3fc0366789cc9e53" +checksum = "f796020459775391094b9dcd133f01b5127059fe167cf412b2d1aed23fe0e52f" dependencies = [ "anyhow", "async-trait", @@ -7808,6 +7808,7 @@ dependencies = [ "tracing", "vise", "zksync_concurrency", + "zksync_consensus_crypto", "zksync_consensus_roles", "zksync_protobuf", "zksync_protobuf_build", @@ -7815,9 +7816,9 @@ dependencies = [ [[package]] name = "zksync_consensus_utils" -version = "0.1.0-rc.1" +version = "0.1.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c3d9b3b6b795ce16e0ead2b8813a2f7a1a01c9a9e3fb50993d6ecbfcdbca98" +checksum = "587de103f745d0b88b49a9fb98cb002c4b7ce6ad042e17845091dce67b8aa984" dependencies = [ "anyhow", "rand 0.8.5", @@ -8133,9 +8134,9 @@ dependencies = [ [[package]] name = "zksync_protobuf" -version = "0.1.0-rc.1" +version = "0.1.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe77d262206bb22f4bc26e75b68466b2e7043baa4963fe97190ce8540a5d700" +checksum = "d86baa84d8bbbbeea269c0f99aca88364e4fd2a08e6ae7051ff87317132b4ef9" dependencies = [ "anyhow", "bit-vec", @@ -8154,9 +8155,9 @@ dependencies = [ [[package]] name = "zksync_protobuf_build" -version = "0.1.0-rc.1" +version = "0.1.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1205d607aa7291e3e016ce202d97cd7eb7d232913076dd873cbe48d564bf656" +checksum = "f221ce83f4622c3d8732d09f4461d116d7b10f1cc9d1d1cd014c1fa836c168e6" dependencies = [ "anyhow", "heck 0.5.0", diff --git a/zk_toolbox/Cargo.lock b/zk_toolbox/Cargo.lock index 29547a4b47fe..5b85dc5f8e99 100644 --- a/zk_toolbox/Cargo.lock +++ b/zk_toolbox/Cargo.lock @@ -6380,9 +6380,9 @@ dependencies = [ [[package]] name = "zksync_concurrency" -version = "0.1.0-rc.1" +version = "0.1.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28279a743cd2ec5a0e3f0fec31b2e4fdd509d0b513e0aaeb000200ce464123e5" +checksum = "1af85d9a31c534a29877c88474cf5f1c46ad25f7c48efff61ea40f4aa83c5459" dependencies = [ "anyhow", "once_cell", @@ -6414,9 +6414,9 @@ dependencies = [ [[package]] name = "zksync_consensus_utils" -version = "0.1.0-rc.1" +version = "0.1.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c3d9b3b6b795ce16e0ead2b8813a2f7a1a01c9a9e3fb50993d6ecbfcdbca98" +checksum = "587de103f745d0b88b49a9fb98cb002c4b7ce6ad042e17845091dce67b8aa984" dependencies = [ "anyhow", "rand", @@ -6476,9 +6476,9 @@ dependencies = [ [[package]] name = "zksync_protobuf" -version = "0.1.0-rc.1" +version = "0.1.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe77d262206bb22f4bc26e75b68466b2e7043baa4963fe97190ce8540a5d700" +checksum = "d86baa84d8bbbbeea269c0f99aca88364e4fd2a08e6ae7051ff87317132b4ef9" dependencies = [ "anyhow", "bit-vec", @@ -6497,9 +6497,9 @@ dependencies = [ [[package]] name = "zksync_protobuf_build" -version = "0.1.0-rc.1" +version = "0.1.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1205d607aa7291e3e016ce202d97cd7eb7d232913076dd873cbe48d564bf656" +checksum = "f221ce83f4622c3d8732d09f4461d116d7b10f1cc9d1d1cd014c1fa836c168e6" dependencies = [ "anyhow", "heck 0.5.0", From 11aa47599016d00437f2adedd904afe5bb284a15 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Tue, 9 Jul 2024 23:15:25 +0100 Subject: [PATCH 13/15] Update core/node/consensus/src/storage/store.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bruno França --- core/node/consensus/src/storage/store.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/node/consensus/src/storage/store.rs b/core/node/consensus/src/storage/store.rs index 9f00590fe53f..cc9b0bad2b78 100644 --- a/core/node/consensus/src/storage/store.rs +++ b/core/node/consensus/src/storage/store.rs @@ -446,7 +446,7 @@ impl storage::PersistentBatchStore for Store { self.batches_persisted.clone() } - /// Get the earliest L1 batche for which there is no corresponding L1 batch quorum certificate, + /// Get the earliest L1 batch for which there is no corresponding L1 batch quorum certificate, /// and thus it potentially needs to be signed by attesters. async fn earliest_batch_number_to_sign( &self, From e952e1a2887cf6c54d5ef57b77366c10944d4e71 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Wed, 10 Jul 2024 13:00:25 +0100 Subject: [PATCH 14/15] BFT-474: Raise the batch limit to 5000 blocks --- core/lib/protobuf_config/src/consensus.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/core/lib/protobuf_config/src/consensus.rs b/core/lib/protobuf_config/src/consensus.rs index fb3954d20e5d..a659a6f16abc 100644 --- a/core/lib/protobuf_config/src/consensus.rs +++ b/core/lib/protobuf_config/src/consensus.rs @@ -108,10 +108,13 @@ impl ProtoRepr for proto::Config { let max_batch_size = match self.max_batch_size { Some(x) => x.try_into().context("max_batch_size")?, None => { - // Compute a default batch size: the batch interval is ~1 minute, - // so there will be ~60 blocks, and an Ethereum Merkle proof is ~1kB. - // Using 100 to be generous. - max_payload_size * 100 + kB + // Compute a default batch size, so operators are not caught out by the missing setting + // while we're still working on batch syncing. The batch interval is ~1 minute, + // so there will be ~60 blocks, and an Ethereum Merkle proof is ~1kB, but under high + // traffic there can be thousands of huge transactions that quickly fill up blocks + // and there could be more blocks in a batch then expected. We chose a generous + // limit so as not to prevent any legitimate batch from being transmitted. + max_payload_size * 5000 + kB } }; From ef8d25dfc3fbc6fd0e215487b2a828b2b64c6ff2 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Wed, 10 Jul 2024 13:15:27 +0100 Subject: [PATCH 15/15] BFT-474: Removed min batch number query --- ...a2f2d19eead58df0eca9f985027aca7350530.json | 22 -------- core/lib/dal/src/consensus_dal.rs | 53 ------------------- core/node/consensus/src/storage/connection.rs | 16 ------ core/node/consensus/src/storage/store.rs | 33 +++++++----- 4 files changed, 20 insertions(+), 104 deletions(-) delete mode 100644 core/lib/dal/.sqlx/query-d38d07f12619081a9123080c063a2f2d19eead58df0eca9f985027aca7350530.json diff --git a/core/lib/dal/.sqlx/query-d38d07f12619081a9123080c063a2f2d19eead58df0eca9f985027aca7350530.json b/core/lib/dal/.sqlx/query-d38d07f12619081a9123080c063a2f2d19eead58df0eca9f985027aca7350530.json deleted file mode 100644 index 8e80801b24c3..000000000000 --- a/core/lib/dal/.sqlx/query-d38d07f12619081a9123080c063a2f2d19eead58df0eca9f985027aca7350530.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT\n MIN(b.number) AS \"number\"\n FROM\n l1_batches b\n LEFT JOIN l1_batches_consensus c ON b.number = c.l1_batch_number\n WHERE\n b.number >= $1\n AND c.l1_batch_number IS NULL\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "number", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - null - ] - }, - "hash": "d38d07f12619081a9123080c063a2f2d19eead58df0eca9f985027aca7350530" -} diff --git a/core/lib/dal/src/consensus_dal.rs b/core/lib/dal/src/consensus_dal.rs index 5a3e8a05d662..7655abbe230c 100644 --- a/core/lib/dal/src/consensus_dal.rs +++ b/core/lib/dal/src/consensus_dal.rs @@ -461,40 +461,6 @@ impl ConsensusDal<'_, '_> { .number .map(|number| attester::BatchNumber(number as u64))) } - - /// Get the earliest of L1 batch which does not have a corresponding quorum certificate - /// and need signatures to be gossiped and collected. - /// - /// On the main node this means every L1 batch, because we need QC over all of them to be - /// able to submit them to L1. Replicas don't necessarily have to have the QC, because once - /// the batch is on L1 and it's final, they can get the batch from there and don't need the - /// attestations. The caller will have to choose the `min_batch_number` accordingly. - pub async fn earliest_batch_number_to_sign( - &mut self, - min_batch_number: attester::BatchNumber, - ) -> DalResult> { - let row = sqlx::query!( - r#" - SELECT - MIN(b.number) AS "number" - FROM - l1_batches b - LEFT JOIN l1_batches_consensus c ON b.number = c.l1_batch_number - WHERE - b.number >= $1 - AND c.l1_batch_number IS NULL - "#, - min_batch_number.0 as i64 - ) - .instrument("earliest_batch_number_to_sign") - .report_latency() - .fetch_one(self.storage) - .await?; - - Ok(row - .number - .map(|number| attester::BatchNumber(number as u64))) - } } #[cfg(test)] @@ -634,24 +600,5 @@ mod tests { .insert_mock_l1_batch(&create_l1_batch_header(batch_number + 1)) .await .unwrap(); - - // Check the earliest batch number to be signed at various points. - for (i, (min_l1_batch_number, want_earliest)) in [ - (0, Some(batch_number - 2)), // We inserted 2 unsigned batches before the first cert - (batch_number, Some(batch_number + 1)), // This one has the corresponding cert - (batch_number + 1, Some(batch_number + 1)), // This is the one we inserted later without a cert - (batch_number + 2, None), // Querying beyond the last one - ] - .into_iter() - .enumerate() - { - let min_batch_number = attester::BatchNumber(u64::from(min_l1_batch_number)); - let earliest = conn - .consensus_dal() - .earliest_batch_number_to_sign(min_batch_number) - .await - .unwrap(); - assert_eq!(earliest.map(|n| n.0 as u32), want_earliest, "test case {i}"); - } } } diff --git a/core/node/consensus/src/storage/connection.rs b/core/node/consensus/src/storage/connection.rs index e73125da5873..ad27490bfa81 100644 --- a/core/node/consensus/src/storage/connection.rs +++ b/core/node/consensus/src/storage/connection.rs @@ -430,20 +430,4 @@ impl<'a> Connection<'a> { last, }) } - - /// Wrapper for `consensus_dal().earliest_batch_number_to_sign()`. - pub async fn earliest_batch_number_to_sign( - &mut self, - ctx: &ctx::Ctx, - min_batch_number: attester::BatchNumber, - ) -> ctx::Result> { - Ok(ctx - .wait( - self.0 - .consensus_dal() - .earliest_batch_number_to_sign(min_batch_number), - ) - .await? - .context("earliest_batch_number_to_sign()")?) - } } diff --git a/core/node/consensus/src/storage/store.rs b/core/node/consensus/src/storage/store.rs index cc9b0bad2b78..ad8f4948831b 100644 --- a/core/node/consensus/src/storage/store.rs +++ b/core/node/consensus/src/storage/store.rs @@ -446,26 +446,33 @@ impl storage::PersistentBatchStore for Store { self.batches_persisted.clone() } - /// Get the earliest L1 batch for which there is no corresponding L1 batch quorum certificate, - /// and thus it potentially needs to be signed by attesters. + /// Get the earliest L1 batch number which has to be (re)signed by a node. + /// + /// Ideally we would make this decision by looking up the last batch submitted to L1, + /// and so it might require a quorum of attesters to sign a certificate for it. async fn earliest_batch_number_to_sign( &self, ctx: &ctx::Ctx, ) -> ctx::Result> { - // TODO: In the future external nodes will be able to ask the main node which L1 batch should be considered final. - // Later when we're fully decentralized the nodes will have to look at L1 instead. - // For now we make a best effort at gossiping votes, and have no way to tell what has been finalized, so we can - // just pick a reasonable maximum number of batches for which we might have to re-submit our signatures. + // This is the rough roadmap of how this logic will evolve: + // 1. Make best effort at gossiping and collecting votes; the `BatchVotes` in consensus only considers the last vote per attesters. + // Still, we can re-sign more than the last batch, anticipating step 2. + // 2. Change `BatchVotes` to handle multiple pending batch numbers, anticipating that batch intervals might decrease dramatically. + // 3. Ask the Main Node what is the earliest batch number that it still expects votes for (ie. what is the last submission + 1). + // 4. Look at L1 to figure out what is the last submssion, and sign after that. + + // Originally this method returned all unsigned batch numbers by doing a DAL query, but we decided it shoudl be okay and cheap + // to resend signatures for already signed batches, and we don't have to worry about skipping them. Because of that, we also + // didn't think it makes sense to query the database for the earliest unsigned batch *after* the submission, because we might + // as well just re-sign everything. Until we have a way to argue about the "last submission" we just re-sign the last 10 to + // try to produce as many QCs as the voting register allows, within reason. + let Some(last_batch_number) = self.last_batch(ctx).await? else { return Ok(None); }; - let min_batch_number = attester::BatchNumber(last_batch_number.0.saturating_sub(10)); - - self.conn(ctx) - .await? - .earliest_batch_number_to_sign(ctx, min_batch_number) - .await - .wrap("earliest_batch_number_to_sign") + Ok(Some(attester::BatchNumber( + last_batch_number.0.saturating_sub(10), + ))) } /// Get the highest L1 batch number from storage.