Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 12 additions & 22 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 10 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -211,16 +211,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.4"
zksync_consensus_bft = "=0.1.0-rc.4"
zksync_consensus_crypto = "=0.1.0-rc.4"
zksync_consensus_executor = "=0.1.0-rc.4"
zksync_consensus_network = "=0.1.0-rc.4"
zksync_consensus_roles = "=0.1.0-rc.4"
zksync_consensus_storage = "=0.1.0-rc.4"
zksync_consensus_utils = "=0.1.0-rc.4"
zksync_protobuf = "=0.1.0-rc.4"
zksync_protobuf_build = "=0.1.0-rc.4"
zksync_concurrency = { git = "https://github.com/matter-labs/era-consensus.git", branch = "update_committee_types" }
zksync_consensus_bft = { git = "https://github.com/matter-labs/era-consensus.git", branch = "update_committee_types" }
zksync_consensus_crypto = { git = "https://github.com/matter-labs/era-consensus.git", branch = "update_committee_types" }
zksync_consensus_executor = { git = "https://github.com/matter-labs/era-consensus.git", branch = "update_committee_types" }
zksync_consensus_network = { git = "https://github.com/matter-labs/era-consensus.git", branch = "update_committee_types" }
zksync_consensus_roles = { git = "https://github.com/matter-labs/era-consensus.git", branch = "update_committee_types" }
zksync_consensus_storage = { git = "https://github.com/matter-labs/era-consensus.git", branch = "update_committee_types" }
zksync_consensus_utils = { git = "https://github.com/matter-labs/era-consensus.git", branch = "update_committee_types" }
zksync_protobuf = { git = "https://github.com/matter-labs/era-consensus.git", branch = "update_committee_types" }
zksync_protobuf_build = { git = "https://github.com/matter-labs/era-consensus.git", branch = "update_committee_types" }

# "Local" dependencies
zksync_multivm = { version = "0.1.0", path = "core/lib/multivm" }
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ALTER TABLE l1_batches_consensus
DROP COLUMN validator_committee,
DROP COLUMN attester_committee;

ALTER TABLE l1_batches_consensus
ALTER COLUMN certificate SET NOT NULL;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
ALTER TABLE l1_batches_consensus
ADD validator_committee JSONB NULL,
ADD attester_committee JSONB NULL;

ALTER TABLE l1_batches_consensus
ALTER COLUMN certificate DROP NOT NULL;

--ALTER TABLE l1_batches_consensus DROP CONSTRAINT l1_batches_consensus_certificate_check;
--
--ALTER TABLE l1_batches_consensus ADD CONSTRAINT l1_batches_consensus_certificate_check
--CHECK (certificate IS NULL OR ((certificate->'message'->>'number')::numeric = l1_batch_number));
--
101 changes: 96 additions & 5 deletions core/lib/dal/src/consensus_dal.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
use anyhow::Context as _;
use bigdecimal::Zero as _;
use zksync_consensus_roles::{attester, validator};
use zksync_consensus_roles::{
attester,
attester::{AttesterCommittee, BatchNumber},
validator,
validator::{ValidatorCommittee, WeightedValidator},
};
use zksync_consensus_storage::{BlockStoreState, ReplicaState};
use zksync_db_connection::{
connection::Connection,
error::{DalError, DalResult, SqlxContext},
instrument::{InstrumentExt, Instrumented},
};
use zksync_protobuf::ProtoFmt;
use zksync_types::L2BlockNumber;

pub use crate::consensus::Payload;
Expand Down Expand Up @@ -317,7 +323,39 @@ impl ConsensusDal<'_, '_> {
else {
return Ok(None);
};
Ok(Some(zksync_protobuf::serde::deserialize(row.certificate)?))
Ok(Some(zksync_protobuf::serde::deserialize(
row.certificate.unwrap(),
)?))
}

pub async fn batch_committees(
&mut self,
batch_number: attester::BatchNumber,
) -> anyhow::Result<Option<(validator::ValidatorCommittee, attester::AttesterCommittee)>> {
let Some(row) = sqlx::query!(
r#"
SELECT
validator_committee,
attester_committee
FROM
l1_batches_consensus
WHERE
l1_batch_number = $1
"#,
i64::try_from(batch_number.0)?
)
.instrument("batch_committees")
.report_latency()
.fetch_optional(self.storage)
.await?
else {
return Ok(None);
};

Ok(Some((
zksync_protobuf::serde::deserialize(row.validator_committee.unwrap())?,
zksync_protobuf::serde::deserialize(row.attester_committee.unwrap())?,
)))
}

/// Fetches a range of L2 blocks from storage and converts them to `Payload`s.
Expand Down Expand Up @@ -402,6 +440,48 @@ impl ConsensusDal<'_, '_> {
Ok(())
}

pub async fn insert_batch_committees(
&mut self,
number: BatchNumber,
validator_committee: ValidatorCommittee,
attester_committee: AttesterCommittee,
) -> anyhow::Result<()> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we are going to query the last batch with committees/certificate, then keeping them in the same table makes little sense, because we will need extra indices for efficient lookups. Do we really want to go this way?

Copy link
Contributor Author

@moshababo moshababo Jul 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Querying the last batch with committees is a one-time read on server start, so I didn’t thought it’s a big deal. And I don’t see such an index for the query of the last batch with certificate (unless it’s applied internally via the toolchain).

In the overall, I’m not against separating the tables, and originally suggested that. IIRC @RomanBrodetski thought it’s an overkill, and that having all info in respect to a given batch in one place is useful.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no index, because the the table serves as index for itself when it has just 1 non null column. With 2 columns, it won't be the case.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because we will need extra indices for efficient lookups.

why exactly? select ... order by ID desc where certificate is not null will only scan the rows for which there is committee but not certificate. Given that it happens on startup, it shouldn't be a problem - am I missing smt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no index, because the the table serves as index for itself when it has just 1 non null column. With 2 columns, it won't be the case.

Right, I overlooked that in that case there's no need for WHERE clause.

why exactly? select ... order by ID desc where certificate is not null will only scan the rows for which there is committee but not certificate. Given that it happens on startup, it shouldn't be a problem - am I missing smt?

If column X is NOT NULL, there's no need for WHERE X IS NOT NULL, and SELECT MAX(PK) alone is sufficient.

Since the NULL column is the certificate, and not the committee, this won't happen just on startup. However, I'm not sure about the frequency of this query and whether it justifies an index.

Copy link
Contributor

@aakoshh aakoshh Aug 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW I would keep the committee in a separate table. As I understand we are doing this without concern for performance, but there are many ways to store the committee, and some don't involve repeating the entire committee in every batch, only when it changes. To keep our options open for future changes, I would keep them separate from the beginning, rather than start messing around with existing constraints to make room for this in the same table, having to revisit the (luckily few) existing queries where we now have to add filtering, turning inserts into updates.

let res = sqlx::query!(
r#"
INSERT INTO
l1_batches_consensus (
l1_batch_number,
certificate,
validator_committee,
attester_committee,
created_at,
updated_at
)
VALUES
($1, NULL, $2, $3, NOW(), NOW())
ON CONFLICT (l1_batch_number) DO
UPDATE
SET
validator_committee = EXCLUDED.validator_committee,
attester_committee = EXCLUDED.attester_committee,
updated_at = NOW();
"#,
i64::try_from(number.0).context("overflow")?.into(),
zksync_protobuf::serde::serialize(&validator_committee, serde_json::value::Serializer)
.unwrap(),
zksync_protobuf::serde::serialize(&attester_committee, serde_json::value::Serializer)
.unwrap(),
)
.instrument("insert_batch_committees")
.report_latency()
.execute(self.storage)
.await?;
if res.rows_affected().is_zero() {
tracing::debug!(l1_batch_number = ?number, "duplicate batch certificate");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
tracing::debug!(l1_batch_number = ?number, "duplicate batch certificate");
tracing::debug!(l1_batch_number = ?number, "duplicate batch committee");

}
Ok(())
}

/// Inserts a certificate for the L1 batch.
/// Noop if a certificate for the same L1 batch is already present.
/// No verification is performed - it cannot be performed due to circular dependency on
Expand All @@ -413,10 +493,21 @@ impl ConsensusDal<'_, '_> {
let res = sqlx::query!(
r#"
INSERT INTO
l1_batches_consensus (l1_batch_number, certificate, created_at, updated_at)
l1_batches_consensus (
l1_batch_number,
certificate,
validator_committee,
attester_committee,
created_at,
updated_at
)
VALUES
($1, $2, NOW(), NOW())
ON CONFLICT (l1_batch_number) DO NOTHING
($1, $2, NULL, NULL, NOW(), NOW())
ON CONFLICT (l1_batch_number) DO
UPDATE
SET
certificate = EXCLUDED.certificate,
updated_at = NOW();
"#,
i64::try_from(cert.message.number.0).context("overflow")?,
// Unwrap is ok, because serialization should always succeed.
Expand Down
3 changes: 2 additions & 1 deletion core/node/consensus/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use zksync_config::{
};
use zksync_consensus_crypto::{Text, TextFmt};
use zksync_consensus_executor as executor;
use zksync_consensus_roles::{attester, node, validator};
use zksync_consensus_roles::{attester, node, validator, validator::Signature};

fn read_secret_text<T: TextFmt>(text: Option<&Secret<String>>) -> anyhow::Result<Option<T>> {
text.map(|text| Text::new(text.expose_secret()).decode())
Expand Down Expand Up @@ -63,6 +63,7 @@ impl GenesisSpec {
Ok(validator::WeightedValidator {
key: Text::new(&v.key.0).decode().context("key").context(i)?,
weight: v.weight,
pop: Signature::decode(Text::new("")).unwrap(), // TODO(moshababo): implement
})
})
.collect::<anyhow::Result<_>>()
Expand Down
36 changes: 35 additions & 1 deletion core/node/consensus/src/storage/connection.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
use anyhow::Context as _;
use zksync_concurrency::{ctx, error::Wrap as _, time};
use zksync_consensus_crypto::keccak256::Keccak256;
use zksync_consensus_roles::{attester, validator};
use zksync_consensus_roles::{
attester,
attester::{AttesterCommittee, BatchNumber},
validator,
validator::ValidatorCommittee,
};
use zksync_consensus_storage::{self as storage, BatchStoreState};
use zksync_dal::{consensus_dal, consensus_dal::Payload, Core, CoreDal, DalError};
use zksync_l1_contract_interface::i_executor::structures::StoredBatchInfo;
Expand Down Expand Up @@ -138,6 +143,23 @@ impl<'a> Connection<'a> {
.map_err(E::Other)?)
}

/// Wrapper for `consensus_dal().insert_batch_committees()`.
pub async fn insert_batch_committees(
&mut self,
ctx: &ctx::Ctx,
number: BatchNumber,
validator_committee: ValidatorCommittee,
attester_committee: AttesterCommittee,
) -> ctx::Result<()> {
ctx.wait(self.0.consensus_dal().insert_batch_committees(
number,
validator_committee,
attester_committee,
))
.await??;
Ok(())
}

/// Wrapper for `consensus_dal().replica_state()`.
pub async fn replica_state(&mut self, ctx: &ctx::Ctx) -> ctx::Result<storage::ReplicaState> {
Ok(ctx
Expand Down Expand Up @@ -339,6 +361,18 @@ impl<'a> Connection<'a> {
.context("batch_certificate()")?)
}

/// Wrapper for `consensus_dal().batch_committees()`.
pub async fn batch_committees(
&mut self,
ctx: &ctx::Ctx,
batch_number: attester::BatchNumber,
) -> ctx::Result<Option<(validator::ValidatorCommittee, attester::AttesterCommittee)>> {
Ok(ctx
.wait(self.0.consensus_dal().batch_committees(batch_number))
.await?
.context("batch_committees()")?)
}

/// Wrapper for `blocks_dal().get_l2_block_range_of_l1_batch()`.
pub async fn get_l2_block_range_of_l1_batch(
&mut self,
Expand Down
Loading
Loading