-
Notifications
You must be signed in to change notification settings - Fork 2.1k
[WIP] feat(consensus): committees data extractor (BFT-443) #2518
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
4bb671a
cfd7316
4fc93f2
c4d51da
2ed908c
2b41130
b8e4216
2824931
65d3fa3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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)); | ||
-- |
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; | ||||||
|
@@ -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(), | ||||||
moshababo marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
)?)) | ||||||
} | ||||||
|
||||||
pub async fn batch_committees( | ||||||
&mut self, | ||||||
batch_number: attester::BatchNumber, | ||||||
) -> anyhow::Result<Option<(validator::ValidatorCommittee, attester::AttesterCommittee)>> { | ||||||
moshababo marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
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())?, | ||||||
moshababo marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
))) | ||||||
} | ||||||
|
||||||
/// Fetches a range of L2 blocks from storage and converts them to `Payload`s. | ||||||
|
@@ -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<()> { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
why exactly? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Right, I overlooked that in that case there's no need for
If column X is NOT NULL, there's no need for 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
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 | ||||||
|
@@ -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. | ||||||
|
Uh oh!
There was an error while loading. Please reload this page.