Skip to content

Commit 1bb82d6

Browse files
authored
feat(en): Improved en commitment generation error handling (#4483)
1 parent 468cec9 commit 1bb82d6

File tree

6 files changed

+75
-50
lines changed

6 files changed

+75
-50
lines changed

core/bin/custom_genesis_export/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ async fn main() -> anyhow::Result<()> {
120120
.protocol_version
121121
.ok_or(anyhow::anyhow!("No bootloader_hash specified"))?
122122
.minor,
123-
);
123+
)?;
124124

125125
genesis_config.genesis_root_hash = Some(genesis_batch_params.root_hash);
126126
genesis_config.rollup_last_leaf_index = Some(genesis_batch_params.rollup_last_leaf_index);

core/lib/types/src/commitment/mod.rs

Lines changed: 61 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use std::{collections::HashMap, convert::TryFrom};
1010

1111
use serde::{Deserialize, Serialize};
12+
use thiserror::Error;
1213
pub use zksync_basic_types::commitment::{L1BatchCommitmentMode, PubdataParams, PubdataType};
1314
use zksync_contracts::BaseSystemContractsHashes;
1415
use zksync_crypto_primitives::hasher::{keccak::KeccakHasher, Hasher};
@@ -38,6 +39,21 @@ use crate::{
3839
#[cfg(test)]
3940
mod tests;
4041

42+
#[derive(Debug, Error)]
43+
pub enum CommitmentValidationError {
44+
#[error("State diff hash mismatch: expected {expected}, got {actual}")]
45+
StateDiffHashMismatch { expected: H256, actual: H256 },
46+
#[error("Blob linear hashes mismatch: expected {expected:?}, got {actual:?}")]
47+
BlobLinearHashesMismatch {
48+
expected: Vec<H256>,
49+
actual: Vec<H256>,
50+
},
51+
#[error("L2 L1 logs tree root mismatch: expected {expected}, got {actual}")]
52+
L2L1LogsTreeRootMismatch { expected: H256, actual: H256 },
53+
#[error("Serialized size for BlockPassThroughData is bigger than expected: expected {expected}, got {actual}")]
54+
SerializedSizeMismatch { expected: usize, actual: usize },
55+
}
56+
4157
/// Type that can be serialized for commitment.
4258
pub trait SerializeCommitment {
4359
/// Size of the structure in bytes.
@@ -335,7 +351,7 @@ pub enum L1BatchAuxiliaryOutput {
335351
}
336352

337353
impl L1BatchAuxiliaryOutput {
338-
fn new(input: CommitmentInput) -> Self {
354+
fn new(input: CommitmentInput) -> Result<Self, CommitmentValidationError> {
339355
match input {
340356
CommitmentInput::PreBoojum {
341357
common: common_input,
@@ -365,14 +381,14 @@ impl L1BatchAuxiliaryOutput {
365381
let repeated_writes_compressed = pre_boojum_serialize_commitments(&repeated_writes);
366382
let repeated_writes_hash = H256::from(keccak256(&repeated_writes_compressed));
367383

368-
Self::PreBoojum {
384+
Ok(Self::PreBoojum {
369385
common: common_output,
370386
l2_l1_logs_linear_hash,
371387
initial_writes_compressed,
372388
initial_writes_hash,
373389
repeated_writes_compressed,
374390
repeated_writes_hash,
375-
}
391+
})
376392
}
377393
CommitmentInput::PostBoojum {
378394
common: common_input,
@@ -419,10 +435,12 @@ impl L1BatchAuxiliaryOutput {
419435
.then_some(log.0.value)
420436
})
421437
.expect("Failed to find state diff hash in system logs");
422-
assert_eq!(
423-
state_diffs_hash, state_diff_hash_from_logs,
424-
"State diff hash mismatch"
425-
);
438+
if state_diffs_hash != state_diff_hash_from_logs {
439+
return Err(CommitmentValidationError::StateDiffHashMismatch {
440+
expected: state_diff_hash_from_logs,
441+
actual: state_diffs_hash,
442+
});
443+
}
426444

427445
let blob_linear_hashes_from_logs =
428446
parse_system_logs_for_blob_hashes_pre_gateway(
@@ -431,10 +449,12 @@ impl L1BatchAuxiliaryOutput {
431449
);
432450
let blob_linear_hashes: Vec<_> =
433451
blob_hashes.iter().map(|b| b.linear_hash).collect();
434-
assert_eq!(
435-
blob_linear_hashes, blob_linear_hashes_from_logs,
436-
"Blob linear hashes mismatch"
437-
);
452+
if blob_linear_hashes != blob_linear_hashes_from_logs {
453+
return Err(CommitmentValidationError::BlobLinearHashesMismatch {
454+
expected: blob_linear_hashes_from_logs,
455+
actual: blob_linear_hashes,
456+
});
457+
}
438458
}
439459

440460
let l2_to_l1_logs_tree_root_from_logs = system_logs
@@ -444,13 +464,15 @@ impl L1BatchAuxiliaryOutput {
444464
.then_some(log.0.value)
445465
})
446466
.expect("Failed to find L2 to L1 logs tree root in system logs");
447-
assert_eq!(
448-
l2_l1_logs_merkle_root, l2_to_l1_logs_tree_root_from_logs,
449-
"L2 L1 logs tree root mismatch"
450-
);
467+
if l2_l1_logs_merkle_root != l2_to_l1_logs_tree_root_from_logs {
468+
return Err(CommitmentValidationError::L2L1LogsTreeRootMismatch {
469+
expected: l2_to_l1_logs_tree_root_from_logs,
470+
actual: l2_l1_logs_merkle_root,
471+
});
472+
}
451473
}
452474

453-
Self::PostBoojum {
475+
Ok(Self::PostBoojum {
454476
common: common_output,
455477
system_logs_linear_hash,
456478
state_diffs_compressed,
@@ -459,7 +481,7 @@ impl L1BatchAuxiliaryOutput {
459481
blob_hashes,
460482
local_root,
461483
aggregation_root,
462-
}
484+
})
463485
}
464486
}
465487
}
@@ -589,24 +611,25 @@ struct L1BatchPassThroughData {
589611
}
590612

591613
impl L1BatchPassThroughData {
592-
pub fn to_bytes(&self) -> Vec<u8> {
614+
pub fn to_bytes(&self) -> Result<Vec<u8>, CommitmentValidationError> {
593615
// We assume that currently we have only two shared state: Rollup and ZkPorter where porter is always zero
594616
const SERIALIZED_SIZE: usize = 8 + 32 + 8 + 32;
595617
let mut result = Vec::with_capacity(SERIALIZED_SIZE);
596618
for state in self.shared_states.iter() {
597619
result.extend_from_slice(&state.last_leaf_index.to_be_bytes());
598620
result.extend_from_slice(state.root_hash.as_bytes());
599621
}
600-
assert_eq!(
601-
result.len(),
602-
SERIALIZED_SIZE,
603-
"Serialized size for BlockPassThroughData is bigger than expected"
604-
);
605-
result
622+
if result.len() != SERIALIZED_SIZE {
623+
return Err(CommitmentValidationError::SerializedSizeMismatch {
624+
expected: SERIALIZED_SIZE,
625+
actual: result.len(),
626+
});
627+
}
628+
Ok(result)
606629
}
607630

608-
pub fn hash(&self) -> H256 {
609-
H256::from_slice(&keccak256(&self.to_bytes()))
631+
pub fn hash(&self) -> Result<H256, CommitmentValidationError> {
632+
Ok(H256::from_slice(&keccak256(&self.to_bytes()?)))
610633
}
611634
}
612635

@@ -627,7 +650,7 @@ pub struct L1BatchCommitmentHash {
627650
}
628651

629652
impl L1BatchCommitment {
630-
pub fn new(input: CommitmentInput) -> Self {
653+
pub fn new(input: CommitmentInput) -> Result<Self, CommitmentValidationError> {
631654
let meta_parameters = L1BatchMetaParameters {
632655
zkporter_is_available: ZKPORTER_IS_AVAILABLE,
633656
bootloader_code_hash: input.common().bootloader_code_hash,
@@ -636,7 +659,7 @@ impl L1BatchCommitment {
636659
protocol_version: Some(input.common().protocol_version),
637660
};
638661

639-
Self {
662+
Ok(Self {
640663
pass_through_data: L1BatchPassThroughData {
641664
shared_states: vec![
642665
RootState {
@@ -650,9 +673,9 @@ impl L1BatchCommitment {
650673
},
651674
],
652675
},
653-
auxiliary_output: L1BatchAuxiliaryOutput::new(input),
676+
auxiliary_output: L1BatchAuxiliaryOutput::new(input)?,
654677
meta_parameters,
655-
}
678+
})
656679
}
657680

658681
pub fn meta_parameters(&self) -> L1BatchMetaParameters {
@@ -672,25 +695,25 @@ impl L1BatchCommitment {
672695
}
673696
}
674697

675-
pub fn hash(&self) -> L1BatchCommitmentHash {
698+
pub fn hash(&self) -> Result<L1BatchCommitmentHash, CommitmentValidationError> {
676699
let mut result = vec![];
677-
let pass_through_data_hash = self.pass_through_data.hash();
700+
let pass_through_data_hash = self.pass_through_data.hash()?;
678701
result.extend_from_slice(pass_through_data_hash.as_bytes());
679702
let metadata_hash = self.meta_parameters.hash();
680703
result.extend_from_slice(metadata_hash.as_bytes());
681704
let auxiliary_output_hash = self.auxiliary_output.hash();
682705
result.extend_from_slice(auxiliary_output_hash.as_bytes());
683706
let hash = keccak256(&result);
684707
let commitment = H256::from_slice(&hash);
685-
L1BatchCommitmentHash {
708+
Ok(L1BatchCommitmentHash {
686709
pass_through_data: pass_through_data_hash,
687710
aux_output: auxiliary_output_hash,
688711
meta_parameters: metadata_hash,
689712
commitment,
690-
}
713+
})
691714
}
692715

693-
pub fn artifacts(&self) -> L1BatchCommitmentArtifacts {
716+
pub fn artifacts(&self) -> Result<L1BatchCommitmentArtifacts, CommitmentValidationError> {
694717
let (compressed_initial_writes, compressed_repeated_writes, compressed_state_diffs) =
695718
match &self.auxiliary_output {
696719
L1BatchAuxiliaryOutput::PostBoojum {
@@ -708,8 +731,8 @@ impl L1BatchCommitment {
708731
),
709732
};
710733

711-
L1BatchCommitmentArtifacts {
712-
commitment_hash: self.hash(),
734+
Ok(L1BatchCommitmentArtifacts {
735+
commitment_hash: self.hash()?,
713736
l2_l1_merkle_root: self.l2_l1_logs_merkle_root(),
714737
compressed_state_diffs,
715738
zkporter_is_available: self.meta_parameters.zkporter_is_available,
@@ -719,7 +742,7 @@ impl L1BatchCommitment {
719742
local_root: self.auxiliary_output.local_root(),
720743
aggregation_root: self.auxiliary_output.aggregation_root(),
721744
state_diff_hash: self.auxiliary_output.state_diff_hash(),
722-
}
745+
})
723746
}
724747
}
725748

core/lib/types/src/commitment/tests/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ fn run_test(test_name: &str) {
1717
let contents = read_to_string(format!("src/commitment/tests/{test_name}.json")).unwrap();
1818
let commitment_test: CommitmentTest = serde_json::from_str(&contents).unwrap();
1919

20-
let commitment = L1BatchCommitment::new(commitment_test.input);
20+
let commitment = L1BatchCommitment::new(commitment_test.input).unwrap();
2121

2222
assert_eq!(
2323
commitment.pass_through_data,
@@ -28,7 +28,7 @@ fn run_test(test_name: &str) {
2828
commitment.auxiliary_output,
2929
commitment_test.auxiliary_output
3030
);
31-
assert_eq!(commitment.hash(), commitment_test.hashes);
31+
assert_eq!(commitment.hash().unwrap(), commitment_test.hashes);
3232
}
3333

3434
#[test]

core/node/commitment_generator/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,9 +337,9 @@ impl CommitmentGenerator {
337337

338338
let latency =
339339
METRICS.generate_commitment_latency_stage[&CommitmentStage::Calculate].start();
340-
let mut commitment = L1BatchCommitment::new(input);
340+
let mut commitment = L1BatchCommitment::new(input)?;
341341
self.post_process_commitment(&mut commitment, commitment_mode);
342-
let artifacts = commitment.artifacts();
342+
let artifacts = commitment.artifacts()?;
343343
let latency = latency.observe();
344344
tracing::debug!(
345345
"Generated commitment artifacts for L1 batch #{l1_batch_number} in {latency:?}"

core/node/genesis/src/lib.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ pub enum GenesisError {
7474
Other(#[from] anyhow::Error),
7575
#[error("Field: {0} required for genesis")]
7676
MalformedConfig(&'static str),
77+
#[error("Commitment validation error: {0}")]
78+
CommitmentValidation(#[from] zksync_types::commitment::CommitmentValidationError),
7779
}
7880

7981
#[derive(Debug, Clone)]
@@ -191,7 +193,7 @@ pub fn make_genesis_batch_params(
191193
deduped_log_queries: Vec<LogQuery>,
192194
base_system_contract_hashes: BaseSystemContractsHashes,
193195
protocol_version: ProtocolVersionId,
194-
) -> (GenesisBatchParams, L1BatchCommitment) {
196+
) -> Result<(GenesisBatchParams, L1BatchCommitment), GenesisError> {
195197
let storage_logs = deduped_log_queries
196198
.into_iter()
197199
.filter(|log_query| log_query.rw_flag) // only writes
@@ -216,17 +218,17 @@ pub fn make_genesis_batch_params(
216218
base_system_contract_hashes,
217219
protocol_version,
218220
);
219-
let block_commitment = L1BatchCommitment::new(commitment_input);
220-
let commitment = block_commitment.hash().commitment;
221+
let block_commitment = L1BatchCommitment::new(commitment_input)?;
222+
let commitment = block_commitment.hash()?.commitment;
221223

222-
(
224+
Ok((
223225
GenesisBatchParams {
224226
root_hash,
225227
commitment,
226228
rollup_last_leaf_index,
227229
},
228230
block_commitment,
229-
)
231+
))
230232
}
231233

232234
pub async fn insert_genesis_batch_with_custom_state(
@@ -297,7 +299,7 @@ pub async fn insert_genesis_batch_with_custom_state(
297299
deduped_log_queries,
298300
base_system_contract_hashes,
299301
genesis_params.minor_protocol_version(),
300-
);
302+
)?;
301303

302304
save_genesis_l1_batch_metadata(
303305
&mut transaction,

core/node/genesis/src/utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ pub(super) async fn save_genesis_l1_batch_metadata(
154154
.save_l1_batch_tree_data(L1BatchNumber(0), &tree_data)
155155
.await?;
156156

157-
let mut commitment_artifacts = commitment.artifacts();
157+
let mut commitment_artifacts = commitment.artifacts()?;
158158
// `l2_l1_merkle_root` for genesis batch is set to 0 on L1 contract, same must be here.
159159
commitment_artifacts.l2_l1_merkle_root = H256::zero();
160160

0 commit comments

Comments
 (0)