Skip to content

Commit c147b0c

Browse files
authored
feat(metadata-calculator): option to use VM runner for protective reads (#2318)
## What ❔ <!-- What are the changes this PR brings about? --> <!-- Example: This PR adds a PR template to the repo. --> <!-- (For bigger PRs adding more context is appreciated) --> ## Why ❔ <!-- Why are these changes done? What goal do they contribute to? What are the principles behind them? --> <!-- Example: PR templates ensure PR reviewers, observers, and future iterators are in context about the evolution of repos. --> ## Checklist <!-- Check your PR fulfills the following items. --> <!-- For draft PRs check the boxes as you complete them. --> - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`.
1 parent 2b2c790 commit c147b0c

File tree

12 files changed

+277
-91
lines changed

12 files changed

+277
-91
lines changed

core/bin/external_node/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ async fn run_tree(
139139
.merkle_tree_include_indices_and_filters_in_block_cache,
140140
memtable_capacity: config.optional.merkle_tree_memtable_capacity(),
141141
stalled_writes_timeout: config.optional.merkle_tree_stalled_writes_timeout(),
142+
sealed_batches_have_protective_reads: config.optional.protective_reads_persistence_enabled,
142143
recovery: MetadataCalculatorRecoveryConfig {
143144
desired_chunk_size: config.experimental.snapshots_recovery_tree_chunk_size,
144145
parallel_persistence_buffer: config

core/bin/external_node/src/node_builder.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,10 @@ impl ExternalNodeBuilder {
306306
.merkle_tree_include_indices_and_filters_in_block_cache,
307307
memtable_capacity: self.config.optional.merkle_tree_memtable_capacity(),
308308
stalled_writes_timeout: self.config.optional.merkle_tree_stalled_writes_timeout(),
309+
sealed_batches_have_protective_reads: self
310+
.config
311+
.optional
312+
.protective_reads_persistence_enabled,
309313
recovery: MetadataCalculatorRecoveryConfig {
310314
desired_chunk_size: self.config.experimental.snapshots_recovery_tree_chunk_size,
311315
parallel_persistence_buffer: self

core/bin/zksync_server/src/node_builder.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,11 @@ impl MainNodeBuilder {
175175
let merkle_tree_env_config = try_load_config!(self.configs.db_config).merkle_tree;
176176
let operations_manager_env_config =
177177
try_load_config!(self.configs.operations_manager_config);
178+
let state_keeper_env_config = try_load_config!(self.configs.state_keeper_config);
178179
let metadata_calculator_config = MetadataCalculatorConfig::for_main_node(
179180
&merkle_tree_env_config,
180181
&operations_manager_env_config,
182+
&state_keeper_env_config,
181183
);
182184
let mut layer = MetadataCalculatorLayer::new(metadata_calculator_config);
183185
if with_tree_api {

core/lib/dal/.sqlx/query-daa330d43f150824f2195cdbfb96862d6ad0de7c7ca1d5320800f317428f07e1.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/lib/dal/src/vm_runner_dal.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,32 @@ impl VmRunnerDal<'_, '_> {
8484
.await?;
8585
Ok(())
8686
}
87+
88+
pub async fn delete_protective_reads(
89+
&mut self,
90+
last_batch_to_keep: L1BatchNumber,
91+
) -> DalResult<()> {
92+
self.delete_protective_reads_inner(Some(last_batch_to_keep))
93+
.await
94+
}
95+
96+
async fn delete_protective_reads_inner(
97+
&mut self,
98+
last_batch_to_keep: Option<L1BatchNumber>,
99+
) -> DalResult<()> {
100+
let l1_batch_number = last_batch_to_keep.map_or(-1, |number| i64::from(number.0));
101+
sqlx::query!(
102+
r#"
103+
DELETE FROM vm_runner_protective_reads
104+
WHERE
105+
l1_batch_number > $1
106+
"#,
107+
l1_batch_number
108+
)
109+
.instrument("delete_protective_reads")
110+
.with_arg("l1_batch_number", &l1_batch_number)
111+
.execute(self.storage)
112+
.await?;
113+
Ok(())
114+
}
87115
}

core/node/consensus/src/testonly.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use zksync_concurrency::{ctx, error::Wrap as _, scope, sync, time};
77
use zksync_config::{
88
configs,
99
configs::{
10-
chain::OperationsManagerConfig,
10+
chain::{OperationsManagerConfig, StateKeeperConfig},
1111
consensus as config,
1212
database::{MerkleTreeConfig, MerkleTreeMode},
1313
},
@@ -166,8 +166,15 @@ impl StateKeeper {
166166
let operation_manager_config = OperationsManagerConfig {
167167
delay_interval: 100, //`100ms`
168168
};
169-
let config =
170-
MetadataCalculatorConfig::for_main_node(&merkle_tree_config, &operation_manager_config);
169+
let state_keeper_config = StateKeeperConfig {
170+
protective_reads_persistence_enabled: true,
171+
..Default::default()
172+
};
173+
let config = MetadataCalculatorConfig::for_main_node(
174+
&merkle_tree_config,
175+
&operation_manager_config,
176+
&state_keeper_config,
177+
);
171178
let metadata_calculator = MetadataCalculator::new(config, None, pool.0.clone())
172179
.await
173180
.context("MetadataCalculator::new()")?;

core/node/metadata_calculator/src/api_server/tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::tests::{gen_storage_logs, reset_db_state, run_calculator, setup_calcu
1717
async fn merkle_tree_api() {
1818
let pool = ConnectionPool::<Core>::test_pool().await;
1919
let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB");
20-
let (calculator, _) = setup_calculator(temp_dir.path(), pool.clone()).await;
20+
let (calculator, _) = setup_calculator(temp_dir.path(), pool.clone(), true).await;
2121
let api_addr = (Ipv4Addr::LOCALHOST, 0).into();
2222

2323
reset_db_state(&pool, 5).await;
@@ -114,7 +114,7 @@ async fn api_client_unparesable_response_error() {
114114
async fn local_merkle_tree_client() {
115115
let pool = ConnectionPool::<Core>::test_pool().await;
116116
let temp_dir = TempDir::new().expect("failed get temporary directory for RocksDB");
117-
let (calculator, _) = setup_calculator(temp_dir.path(), pool.clone()).await;
117+
let (calculator, _) = setup_calculator(temp_dir.path(), pool.clone(), true).await;
118118

119119
reset_db_state(&pool, 5).await;
120120
let tree_reader = calculator.tree_reader();

core/node/metadata_calculator/src/lib.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::{
1010
use anyhow::Context as _;
1111
use tokio::sync::{oneshot, watch};
1212
use zksync_config::configs::{
13-
chain::OperationsManagerConfig,
13+
chain::{OperationsManagerConfig, StateKeeperConfig},
1414
database::{MerkleTreeConfig, MerkleTreeMode},
1515
};
1616
use zksync_dal::{ConnectionPool, Core};
@@ -89,6 +89,8 @@ pub struct MetadataCalculatorConfig {
8989
pub memtable_capacity: usize,
9090
/// Timeout to wait for the Merkle tree database to run compaction on stalled writes.
9191
pub stalled_writes_timeout: Duration,
92+
/// Whether state keeper writes protective reads when it seals a batch.
93+
pub sealed_batches_have_protective_reads: bool,
9294
/// Configuration specific to the Merkle tree recovery.
9395
pub recovery: MetadataCalculatorRecoveryConfig,
9496
}
@@ -97,6 +99,7 @@ impl MetadataCalculatorConfig {
9799
pub fn for_main_node(
98100
merkle_tree_config: &MerkleTreeConfig,
99101
operation_config: &OperationsManagerConfig,
102+
state_keeper_config: &StateKeeperConfig,
100103
) -> Self {
101104
Self {
102105
db_path: merkle_tree_config.path.clone(),
@@ -109,6 +112,8 @@ impl MetadataCalculatorConfig {
109112
include_indices_and_filters_in_block_cache: false,
110113
memtable_capacity: merkle_tree_config.memtable_capacity(),
111114
stalled_writes_timeout: merkle_tree_config.stalled_writes_timeout(),
115+
sealed_batches_have_protective_reads: state_keeper_config
116+
.protective_reads_persistence_enabled,
112117
// The main node isn't supposed to be recovered yet, so this value doesn't matter much
113118
recovery: MetadataCalculatorRecoveryConfig::default(),
114119
}
@@ -248,7 +253,12 @@ impl MetadataCalculator {
248253
self.health_updater
249254
.update(MerkleTreeHealth::MainLoop(tree_info).into());
250255

251-
let updater = TreeUpdater::new(tree, self.max_l1_batches_per_iter, self.object_store);
256+
let updater = TreeUpdater::new(
257+
tree,
258+
self.max_l1_batches_per_iter,
259+
self.object_store,
260+
self.config.sealed_batches_have_protective_reads,
261+
);
252262
updater
253263
.loop_updating_tree(self.delayer, &self.pool, stop_receiver)
254264
.await

core/node/metadata_calculator/src/recovery/tests.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use tempfile::TempDir;
77
use test_casing::{test_casing, Product};
88
use tokio::sync::mpsc;
99
use zksync_config::configs::{
10-
chain::OperationsManagerConfig,
10+
chain::{OperationsManagerConfig, StateKeeperConfig},
1111
database::{MerkleTreeConfig, MerkleTreeMode},
1212
};
1313
use zksync_dal::CoreDal;
@@ -113,7 +113,7 @@ async fn prepare_recovery_snapshot_with_genesis(
113113
drop(storage);
114114

115115
// Ensure that metadata for L1 batch #1 is present in the DB.
116-
let (calculator, _) = setup_calculator(&temp_dir.path().join("init"), pool).await;
116+
let (calculator, _) = setup_calculator(&temp_dir.path().join("init"), pool, true).await;
117117
let l1_batch_root_hash = run_calculator(calculator).await;
118118

119119
SnapshotRecoveryStatus {
@@ -306,6 +306,10 @@ async fn entire_recovery_workflow(case: RecoveryWorkflowCase) {
306306
let calculator_config = MetadataCalculatorConfig::for_main_node(
307307
&merkle_tree_config,
308308
&OperationsManagerConfig { delay_interval: 50 },
309+
&StateKeeperConfig {
310+
protective_reads_persistence_enabled: true,
311+
..Default::default()
312+
},
309313
);
310314
let mut calculator = MetadataCalculator::new(calculator_config, None, pool.clone())
311315
.await

0 commit comments

Comments
 (0)