Skip to content
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

feat(vm-runner): add protective reads persistence flag for state keeper #2307

Merged
merged 2 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 2 additions & 1 deletion core/bin/zksync_server/src/node_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ impl MainNodeBuilder {
.l2_shared_bridge_addr
.context("L2 shared bridge address")?,
sk_config.l2_block_seal_queue_capacity,
);
)
.with_protective_reads_persistence_enabled(sk_config.protective_reads_persistence_enabled);
let mempool_io_layer = MempoolIOLayer::new(
self.genesis_config.l2_chain_id,
sk_config.clone(),
Expand Down
11 changes: 11 additions & 0 deletions core/lib/config/src/configs/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ pub struct StateKeeperConfig {
/// the recursion layers' circuits.
pub max_circuits_per_batch: usize,

/// Configures whether to persist protective reads when persisting L1 batches in the state keeper.
/// Protective reads can be written asynchronously in VM runner instead.
/// By default, set to `true` as a temporary safety measure.
#[serde(default = "StateKeeperConfig::default_protective_reads_persistence_enabled")]
pub protective_reads_persistence_enabled: bool,

// Base system contract hashes, required only for generating genesis config.
// #PLA-811
#[deprecated(note = "Use GenesisConfig::bootloader_hash instead")]
Expand All @@ -132,6 +138,10 @@ pub struct StateKeeperConfig {
}

impl StateKeeperConfig {
fn default_protective_reads_persistence_enabled() -> bool {
true
}

/// Creates a config object suitable for use in unit tests.
/// Values mostly repeat the values used in the localhost environment.
pub fn for_tests() -> Self {
Expand Down Expand Up @@ -163,6 +173,7 @@ impl StateKeeperConfig {
validation_computational_gas_limit: 300000,
save_call_traces: true,
max_circuits_per_batch: 24100,
protective_reads_persistence_enabled: true,
bootloader_hash: None,
default_aa_hash: None,
l1_batch_commit_data_generator_mode: L1BatchCommitmentMode::Rollup,
Expand Down
1 change: 1 addition & 0 deletions core/lib/config/src/testonly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ impl Distribution<configs::chain::StateKeeperConfig> for EncodeDist {
validation_computational_gas_limit: self.sample(rng),
save_call_traces: self.sample(rng),
max_circuits_per_batch: self.sample(rng),
protective_reads_persistence_enabled: self.sample(rng),
// These values are not involved into files serialization skip them
fee_account_addr: None,
bootloader_hash: None,
Expand Down
1 change: 1 addition & 0 deletions core/lib/env_config/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ mod tests {
)),
l1_batch_commit_data_generator_mode,
max_circuits_per_batch: 24100,
protective_reads_persistence_enabled: true,
}
}

Expand Down
5 changes: 5 additions & 0 deletions core/lib/protobuf_config/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ impl ProtoRepr for proto::StateKeeper {
max_circuits_per_batch: required(&self.max_circuits_per_batch)
.and_then(|x| Ok((*x).try_into()?))
.context("max_circuits_per_batch")?,
protective_reads_persistence_enabled: *required(
&self.protective_reads_persistence_enabled,
)
.context("protective_reads_persistence_enabled")?,

// We need these values only for instantiating configs from environmental variables, so it's not
// needed during the initialization from files
Expand Down Expand Up @@ -115,6 +119,7 @@ impl ProtoRepr for proto::StateKeeper {
validation_computational_gas_limit: Some(this.validation_computational_gas_limit),
save_call_traces: Some(this.save_call_traces),
max_circuits_per_batch: Some(this.max_circuits_per_batch.try_into().unwrap()),
protective_reads_persistence_enabled: Some(this.protective_reads_persistence_enabled),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions core/lib/protobuf_config/src/proto/config/chain.proto
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ message StateKeeper {
optional bool save_call_traces = 22; // required
optional uint64 max_circuits_per_batch = 27; // required
optional uint64 miniblock_max_payload_size = 28; // required
optional bool protective_reads_persistence_enabled = 29; // optional
reserved 23; reserved "virtual_blocks_interval";
reserved 24; reserved "virtual_blocks_per_miniblock";
reserved 26; reserved "enum_index_migration_chunk_size";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ impl WiringLayer for OutputHandlerLayer {
}
if !self.protective_reads_persistence_enabled {
// **Important:** Disabling protective reads persistence is only sound if the node will never
// run a full Merkle tree.
// run a full Merkle tree OR an accompanying protective-reads-writer is being run.
tracing::warn!("Disabling persisting protective reads; this should be safe, but is considered an experimental option at the moment");
persistence = persistence.without_protective_reads();
}
Expand Down
48 changes: 33 additions & 15 deletions core/node/vm_runner/src/impls/protective_reads.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ impl StateKeeperOutputHandler for ProtectiveReadsOutputHandler {
.finished
.as_ref()
.context("L1 batch is not actually finished")?;
let (_, protective_reads): (Vec<StorageLog>, Vec<StorageLog>) = finished_batch
let (_, computed_protective_reads): (Vec<StorageLog>, Vec<StorageLog>) = finished_batch
.final_execution_state
.deduplicated_storage_logs
.iter()
Expand All @@ -149,30 +149,48 @@ impl StateKeeperOutputHandler for ProtectiveReadsOutputHandler {
.pool
.connection_tagged("protective_reads_writer")
.await?;
let mut expected_protective_reads = connection
let mut written_protective_reads = connection
.storage_logs_dedup_dal()
.get_protective_reads_for_l1_batch(updates_manager.l1_batch.number)
.await?;

for protective_read in protective_reads {
let address = protective_read.key.address();
let key = protective_read.key.key();
if !expected_protective_reads.remove(&protective_read.key) {
if !written_protective_reads.is_empty() {
tracing::debug!(
l1_batch_number = %updates_manager.l1_batch.number,
"Protective reads have already been written, validating"
);
for protective_read in computed_protective_reads {
let address = protective_read.key.address();
let key = protective_read.key.key();
if !written_protective_reads.remove(&protective_read.key) {
tracing::error!(
l1_batch_number = %updates_manager.l1_batch.number,
address = %address,
key = %key,
"VM runner produced a protective read that did not happen in state keeper"
);
}
}
for remaining_read in written_protective_reads {
tracing::error!(
l1_batch_number = %updates_manager.l1_batch.number,
address = %address,
key = %key,
"VM runner produced a protective read that did not happen in state keeper"
address = %remaining_read.address(),
key = %remaining_read.key(),
"State keeper produced a protective read that did not happen in VM runner"
);
}
}
for remaining_read in expected_protective_reads {
tracing::error!(
} else {
tracing::debug!(
l1_batch_number = %updates_manager.l1_batch.number,
address = %remaining_read.address(),
key = %remaining_read.key(),
"State keeper produced a protective read that did not happen in VM runner"
"Protective reads have not been written, writing"
);
connection
.storage_logs_dedup_dal()
.insert_protective_reads(
updates_manager.l1_batch.number,
&computed_protective_reads,
)
.await?;
}

Ok(())
Expand Down
1 change: 1 addition & 0 deletions etc/env/file_based/general.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ state_keeper:
validation_computational_gas_limit: 300000
save_call_traces: true
max_circuits_per_batch: 24100
protective_reads_persistence_enabled: true
mempool:
delay_interval: 100
sync_interval_ms: 10
Expand Down
Loading