Skip to content

Commit 3d02076

Browse files
feat(en): seal criteria (#4429)
## 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? --> <!-- The `Why` has to be clear to non-Matter Labs entities running their own ZK Chain --> <!-- Example: PR templates ensure PR reviewers, observers, and future iterators are in context about the evolution of repos. --> ## Is this a breaking change? - [ ] Yes - [ ] No ## Operational changes <!-- Any config changes? Any new flags? Any changes to any scripts? --> <!-- Please add anything that non-Matter Labs entities running their own ZK Chain may need to know --> ## 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 `zkstack dev fmt` and `zkstack dev lint`. --------- Co-authored-by: Artur Puzio <[email protected]>
1 parent a8e5952 commit 3d02076

File tree

23 files changed

+474
-202
lines changed

23 files changed

+474
-202
lines changed

core/bin/external_node/src/node_builder.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,10 @@ impl ExternalNodeBuilder {
191191
.protective_reads_persistence_enabled,
192192
);
193193

194-
let io_layer = ExternalIOLayer::new(self.config.local.networks.l2_chain_id);
194+
let io_layer = ExternalIOLayer::new(
195+
self.config.local.networks.l2_chain_id,
196+
self.config.local.node_sync.validate_seal_criteria,
197+
);
195198

196199
// We only need call traces on the external node if the `debug_` namespace is enabled.
197200
// TODO(PLA-1153): this is backwards / unobvious. Can readily use `config.state_keeper.save_call_traces` instead.

core/lib/config/src/configs/chain.rs

Lines changed: 73 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,65 @@ pub struct SharedStateKeeperConfig {
5151
pub protective_reads_persistence_enabled: bool,
5252
}
5353

54+
#[derive(Debug, Clone, PartialEq, DescribeConfig, DeserializeConfig)]
55+
pub struct SealCriteriaConfig {
56+
/// The max number of slots for txs in a block before it should be sealed by the slots sealer.
57+
#[config(default_t = 8_192)]
58+
pub transaction_slots: usize,
59+
/// Configuration option for tx to be rejected in case
60+
/// it takes more percentage of the block capacity than this value.
61+
#[config(default_t = 0.95, validate(ZERO_TO_ONE))]
62+
pub reject_tx_at_geometry_percentage: f64,
63+
/// Configuration option for tx to be rejected in case
64+
/// it takes more percentage of the block capacity than this value.
65+
#[config(default_t = 0.95, validate(ZERO_TO_ONE))]
66+
pub reject_tx_at_eth_params_percentage: f64,
67+
/// Configuration option for tx to be rejected in case
68+
/// it takes more percentage of the block capacity than this value.
69+
#[config(default_t = 0.95, validate(ZERO_TO_ONE))]
70+
pub reject_tx_at_gas_percentage: f64,
71+
/// Denotes the percentage of geometry params used in L2 block that triggers L2 block seal.
72+
#[config(default_t = 0.95, validate(ZERO_TO_ONE))]
73+
pub close_block_at_geometry_percentage: f64,
74+
/// Denotes the percentage of L1 params used in L2 block that triggers L2 block seal.
75+
#[config(default_t = 0.95, validate(ZERO_TO_ONE))]
76+
pub close_block_at_eth_params_percentage: f64,
77+
/// Denotes the percentage of L1 gas used in L2 block that triggers L2 block seal.
78+
#[config(default_t = 0.95, validate(ZERO_TO_ONE))]
79+
pub close_block_at_gas_percentage: f64,
80+
/// The maximum amount of pubdata that can be used by the batch.
81+
/// This variable should not exceed:
82+
/// - 128kb for calldata-based rollups
83+
/// - 120kb * n, where `n` is a number of blobs for blob-based rollups
84+
/// - the DA layer's blob size limit for the DA layer-based validiums
85+
/// - 100 MB for the object store-based or no-da validiums
86+
#[config(with = Fallback(SizeUnit::Bytes))]
87+
pub max_pubdata_per_batch: ByteSize,
88+
/// The maximum number of circuits that a batch can support.
89+
/// Note, that this number corresponds to the "base layer" circuits, i.e. it does not include
90+
/// the recursion layers' circuits.
91+
#[config(default_t = 31_100)]
92+
pub max_circuits_per_batch: usize,
93+
}
94+
95+
impl SealCriteriaConfig {
96+
/// Creates a config object suitable for use in unit tests.
97+
/// Values mostly repeat the values used in the localhost environment.
98+
pub fn for_tests() -> Self {
99+
SealCriteriaConfig {
100+
transaction_slots: 250,
101+
max_pubdata_per_batch: ByteSize(100_000),
102+
reject_tx_at_geometry_percentage: 0.95,
103+
reject_tx_at_eth_params_percentage: 0.95,
104+
reject_tx_at_gas_percentage: 0.95,
105+
close_block_at_geometry_percentage: 0.95,
106+
close_block_at_eth_params_percentage: 0.95,
107+
close_block_at_gas_percentage: 0.95,
108+
max_circuits_per_batch: 24100,
109+
}
110+
}
111+
}
112+
54113
/// State keeper config.
55114
///
56115
/// # Developer notes
@@ -61,9 +120,8 @@ pub struct SharedStateKeeperConfig {
61120
pub struct StateKeeperConfig {
62121
#[config(flatten)]
63122
pub shared: SharedStateKeeperConfig,
64-
/// The max number of slots for txs in a block before it should be sealed by the slots sealer.
65-
#[config(default_t = 8_192)]
66-
pub transaction_slots: usize,
123+
#[config(flatten)]
124+
pub seal_criteria: SealCriteriaConfig,
67125

68126
/// Deadline after which an L1 batch is going to be unconditionally sealed.
69127
#[config(deprecated = "block_commit_deadline")]
@@ -85,28 +143,6 @@ pub struct StateKeeperConfig {
85143
#[config(default_t = 15_000_000_000)]
86144
pub max_allowed_l2_tx_gas_limit: u64,
87145

88-
/// Configuration option for tx to be rejected in case
89-
/// it takes more percentage of the block capacity than this value.
90-
#[config(default_t = 0.95, validate(ZERO_TO_ONE))]
91-
pub reject_tx_at_geometry_percentage: f64,
92-
/// Configuration option for tx to be rejected in case
93-
/// it takes more percentage of the block capacity than this value.
94-
#[config(default_t = 0.95, validate(ZERO_TO_ONE))]
95-
pub reject_tx_at_eth_params_percentage: f64,
96-
/// Configuration option for tx to be rejected in case
97-
/// it takes more percentage of the block capacity than this value.
98-
#[config(default_t = 0.95, validate(ZERO_TO_ONE))]
99-
pub reject_tx_at_gas_percentage: f64,
100-
/// Denotes the percentage of geometry params used in L2 block that triggers L2 block seal.
101-
#[config(default_t = 0.95, validate(ZERO_TO_ONE))]
102-
pub close_block_at_geometry_percentage: f64,
103-
/// Denotes the percentage of L1 params used in L2 block that triggers L2 block seal.
104-
#[config(default_t = 0.95, validate(ZERO_TO_ONE))]
105-
pub close_block_at_eth_params_percentage: f64,
106-
/// Denotes the percentage of L1 gas used in L2 block that triggers L2 block seal.
107-
#[config(default_t = 0.95, validate(ZERO_TO_ONE))]
108-
pub close_block_at_gas_percentage: f64,
109-
110146
// Parameters without defaults.
111147
/// The minimal acceptable L2 gas price, i.e. the price that should include the cost of computation/proving as well
112148
/// as potentially premium for congestion.
@@ -125,25 +161,12 @@ pub struct StateKeeperConfig {
125161
pub batch_overhead_l1_gas: u64,
126162
/// The maximum amount of gas that can be used by the batch. This value is derived from the circuits limitation per batch.
127163
pub max_gas_per_batch: u64,
128-
/// The maximum amount of pubdata that can be used by the batch.
129-
/// This variable should not exceed:
130-
/// - 128kb for calldata-based rollups
131-
/// - 120kb * n, where `n` is a number of blobs for blob-based rollups
132-
/// - the DA layer's blob size limit for the DA layer-based validiums
133-
/// - 100 MB for the object store-based or no-da validiums
134-
#[config(with = Fallback(SizeUnit::Bytes))]
135-
pub max_pubdata_per_batch: ByteSize,
136164
/// The version of the fee model to use.
137165
#[config(default_t = FeeModelVersion::V2, with = Serde![str])]
138166
pub fee_model_version: FeeModelVersion,
139167
/// Max number of computational gas that validation step is allowed to take. Also applied on the API server.
140168
#[config(default_t = 300_000)]
141169
pub validation_computational_gas_limit: u32,
142-
/// The maximum number of circuits that a batch can support.
143-
/// Note, that this number corresponds to the "base layer" circuits, i.e. it does not include
144-
/// the recursion layers' circuits.
145-
#[config(default_t = 31_100)]
146-
pub max_circuits_per_batch: usize,
147170
/// Allowed deployers for L2 transactions.
148171
#[config(nest)]
149172
pub deployment_allowlist: Option<DeploymentAllowlist>,
@@ -155,27 +178,19 @@ impl StateKeeperConfig {
155178
pub fn for_tests() -> Self {
156179
Self {
157180
shared: SharedStateKeeperConfig::default(),
158-
transaction_slots: 250,
181+
seal_criteria: SealCriteriaConfig::for_tests(),
159182
l1_batch_commit_deadline: Duration::from_millis(2500),
160183
l2_block_commit_deadline: Duration::from_secs(1),
161184
l2_block_max_payload_size: ByteSize(1_000_000),
162185
max_single_tx_gas: 6000000,
163186
max_allowed_l2_tx_gas_limit: 4000000000,
164-
reject_tx_at_geometry_percentage: 0.95,
165-
reject_tx_at_eth_params_percentage: 0.95,
166-
reject_tx_at_gas_percentage: 0.95,
167-
close_block_at_geometry_percentage: 0.95,
168-
close_block_at_eth_params_percentage: 0.95,
169-
close_block_at_gas_percentage: 0.95,
170187
compute_overhead_part: 0.0,
171188
pubdata_overhead_part: 1.0,
172189
batch_overhead_l1_gas: 800_000,
173190
max_gas_per_batch: 200_000_000,
174-
max_pubdata_per_batch: ByteSize(100_000),
175191
minimal_l2_gas_price: 100000000,
176192
fee_model_version: FeeModelVersion::V2,
177193
validation_computational_gas_limit: 300000,
178-
max_circuits_per_batch: 24100,
179194
deployment_allowlist: None,
180195
}
181196
}
@@ -269,27 +284,29 @@ mod tests {
269284
save_call_traces: false,
270285
protective_reads_persistence_enabled: true,
271286
},
272-
transaction_slots: 50,
287+
seal_criteria: SealCriteriaConfig {
288+
transaction_slots: 50,
289+
close_block_at_eth_params_percentage: 0.2,
290+
close_block_at_gas_percentage: 0.8,
291+
close_block_at_geometry_percentage: 0.5,
292+
reject_tx_at_eth_params_percentage: 0.8,
293+
reject_tx_at_geometry_percentage: 0.3,
294+
reject_tx_at_gas_percentage: 0.5,
295+
max_pubdata_per_batch: ByteSize(131_072),
296+
max_circuits_per_batch: 24100,
297+
},
273298
l1_batch_commit_deadline: Duration::from_millis(2500),
274299
l2_block_commit_deadline: Duration::from_millis(1000),
275300
l2_block_max_payload_size: ByteSize(1_000_000),
276301
max_single_tx_gas: 1_000_000,
277302
max_allowed_l2_tx_gas_limit: 2_000_000_000,
278-
close_block_at_eth_params_percentage: 0.2,
279-
close_block_at_gas_percentage: 0.8,
280-
close_block_at_geometry_percentage: 0.5,
281-
reject_tx_at_eth_params_percentage: 0.8,
282-
reject_tx_at_geometry_percentage: 0.3,
283-
reject_tx_at_gas_percentage: 0.5,
284303
minimal_l2_gas_price: 100000000,
285304
compute_overhead_part: 0.0,
286305
pubdata_overhead_part: 1.0,
287306
batch_overhead_l1_gas: 800_000,
288307
max_gas_per_batch: 200_000_000,
289-
max_pubdata_per_batch: ByteSize(131_072),
290308
fee_model_version: FeeModelVersion::V2,
291309
validation_computational_gas_limit: 10_000_000,
292-
max_circuits_per_batch: 24100,
293310
deployment_allowlist: Some(DeploymentAllowlist::Dynamic(DeploymentAllowlistDynamic {
294311
http_file_url: "http://deployment-allowlist/".to_owned(),
295312
refresh_interval: Duration::from_secs(120),

core/lib/config/src/configs/node_sync.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ pub struct NodeSyncConfig {
1212
/// Maximum number of transactions to process in a single batch
1313
#[config(default_t = NonZeroU64::new(10_000).unwrap())]
1414
pub batch_transaction_updater_batch_size: NonZeroU64,
15+
/// Toggle for disabling seal criteria validation in case of some issues / forced proved batches
16+
#[config(default_t = true)]
17+
pub validate_seal_criteria: bool,
1518
}
1619

1720
#[cfg(test)]
@@ -24,6 +27,7 @@ mod tests {
2427
NodeSyncConfig {
2528
batch_transaction_updater_interval: Duration::from_secs(2),
2629
batch_transaction_updater_batch_size: NonZeroU64::new(100).unwrap(),
30+
validate_seal_criteria: false,
2731
}
2832
}
2933

@@ -32,6 +36,7 @@ mod tests {
3236
let env = r#"
3337
NODE_SYNC_BATCH_TRANSACTION_UPDATER_INTERVAL=2sec
3438
NODE_SYNC_BATCH_TRANSACTION_UPDATER_BATCH_SIZE=100
39+
NODE_SYNC_VALIDATE_SEAL_CRITERIA=false
3540
"#;
3641
let env = Environment::from_dotenv("test.env", env)
3742
.unwrap()
@@ -46,6 +51,7 @@ mod tests {
4651
let yaml = r#"
4752
batch_transaction_updater_interval: 2sec
4853
batch_transaction_updater_batch_size: 100
54+
validate_seal_criteria: false
4955
"#;
5056
let yaml = Yaml::new("test.yml", serde_yaml::from_str(yaml).unwrap()).unwrap();
5157
let config: NodeSyncConfig = test_complete(yaml).unwrap();

core/lib/multivm/src/utils/mod.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,27 @@ pub fn get_max_new_factory_deps(version: VmVersion) -> usize {
653653
}
654654
}
655655

656+
pub fn get_max_vm_pubdata_per_batch(version: VmVersion) -> usize {
657+
match version {
658+
VmVersion::M5WithRefunds
659+
| VmVersion::M5WithoutRefunds
660+
| VmVersion::M6Initial
661+
| VmVersion::M6BugWithCompressionFixed
662+
| VmVersion::Vm1_3_2
663+
| VmVersion::VmVirtualBlocks
664+
| VmVersion::VmVirtualBlocksRefundsEnhancement
665+
| VmVersion::VmBoojumIntegration
666+
| VmVersion::Vm1_4_1
667+
| VmVersion::Vm1_4_2 => crate::vm_1_4_2::constants::MAX_VM_PUBDATA_PER_BATCH,
668+
VmVersion::Vm1_5_0SmallBootloaderMemory
669+
| VmVersion::Vm1_5_0IncreasedBootloaderMemory
670+
| VmVersion::VmGateway
671+
| VmVersion::VmEvmEmulator
672+
| VmVersion::VmEcPrecompiles
673+
| VmVersion::VmInterop => crate::vm_latest::constants::MAX_VM_PUBDATA_PER_BATCH,
674+
}
675+
}
676+
656677
/// Holds information about number of cycles used per circuit type.
657678
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
658679
pub(crate) struct CircuitCycleStatistic {

core/node/da_dispatcher/src/node.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,16 @@ impl WiringLayer for DataAvailabilityDispatcherLayer {
5252
async fn wire(self, input: Self::Input) -> Result<Self::Output, WiringError> {
5353
let da_client = input.da_client;
5454
if let Some(limit) = da_client.blob_size_limit() {
55-
if self.state_keeper_config.max_pubdata_per_batch.0 > limit as u64 {
55+
if self
56+
.state_keeper_config
57+
.seal_criteria
58+
.max_pubdata_per_batch
59+
.0
60+
> limit as u64
61+
{
5662
return Err(WiringError::Configuration(format!(
5763
"Max pubdata per batch is greater than the blob size limit: {} > {} B",
58-
self.state_keeper_config.max_pubdata_per_batch, limit
64+
self.state_keeper_config.seal_criteria.max_pubdata_per_batch, limit
5965
)));
6066
}
6167
}

core/node/eth_sender/src/eth_tx_manager.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ impl EthTxManager {
465465

466466
// Not confirmed transactions, ordered by nonce
467467
for tx in inflight_txs {
468-
tracing::info!(
468+
tracing::trace!(
469469
"Checking tx id: {}, operator_nonce: {:?}, tx nonce: {}",
470470
tx.id,
471471
operator_nonce,
@@ -508,17 +508,12 @@ impl EthTxManager {
508508

509509
tracing::trace!(
510510
"Sender's nonce on finalized block is greater than current tx's nonce. \
511-
Checking transaction with id {}. Tx nonce is equal to {}",
511+
Checking transaction with id {} and type {}. Tx nonce is equal to {}",
512512
tx.id,
513+
tx.tx_type,
513514
tx.nonce,
514515
);
515516

516-
tracing::info!(
517-
"Updating status of tx {} of type {} with nonce {}",
518-
tx.id,
519-
tx.tx_type,
520-
tx.nonce
521-
);
522517
match self.check_all_sending_attempts(storage, &tx).await {
523518
Ok(Some(tx_status)) => {
524519
self.apply_tx_status(storage, &tx, tx_status, l1_block_numbers)

core/node/fee_model/src/node/l1_gas.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ impl L1GasLayer {
6161
pubdata_overhead_part: state_keeper_config.pubdata_overhead_part,
6262
batch_overhead_l1_gas: state_keeper_config.batch_overhead_l1_gas,
6363
max_gas_per_batch: state_keeper_config.max_gas_per_batch,
64-
max_pubdata_per_batch: state_keeper_config.max_pubdata_per_batch.0,
64+
max_pubdata_per_batch: state_keeper_config.seal_criteria.max_pubdata_per_batch.0,
6565
}),
6666
}
6767
}

core/node/node_sync/src/node/external_io.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ use zksync_node_framework::{
77
wiring_layer::{WiringError, WiringLayer},
88
FromContext, IntoContext,
99
};
10-
use zksync_shared_resources::api::SyncState;
10+
use zksync_shared_resources::{api::SyncState, L1BatchCommitmentModeResource};
1111
use zksync_state_keeper::{
1212
node::StateKeeperIOResource,
13-
seal_criteria::{ConditionalSealer, NoopSealer},
13+
seal_criteria::{ConditionalSealer, NoopSealer, PanicSealer},
1414
};
1515
use zksync_types::L2ChainId;
1616
use zksync_web3_decl::client::{DynClient, L2};
@@ -22,13 +22,15 @@ use crate::{ActionQueue, ExternalIO};
2222
#[derive(Debug)]
2323
pub struct ExternalIOLayer {
2424
chain_id: L2ChainId,
25+
should_verify_seal_criteria: bool,
2526
}
2627

2728
#[derive(Debug, FromContext)]
2829
pub struct Input {
2930
app_health: Arc<AppHealthCheck>,
3031
pool: PoolResource<MasterPool>,
3132
main_node_client: Box<DynClient<L2>>,
33+
l1_batch_commit_data_generator_mode: L1BatchCommitmentModeResource,
3234
}
3335

3436
#[derive(Debug, IntoContext)]
@@ -40,8 +42,11 @@ pub struct Output {
4042
}
4143

4244
impl ExternalIOLayer {
43-
pub fn new(chain_id: L2ChainId) -> Self {
44-
Self { chain_id }
45+
pub fn new(chain_id: L2ChainId, should_verify_seal_criteria: bool) -> Self {
46+
Self {
47+
chain_id,
48+
should_verify_seal_criteria,
49+
}
4550
}
4651
}
4752

@@ -76,7 +81,13 @@ impl WiringLayer for ExternalIOLayer {
7681
.context("Failed initializing I/O for external node state keeper")?;
7782

7883
// Create sealer.
79-
let sealer = Arc::new(NoopSealer);
84+
let sealer: Arc<dyn ConditionalSealer> = if self.should_verify_seal_criteria {
85+
Arc::new(PanicSealer::new(
86+
input.l1_batch_commit_data_generator_mode.0,
87+
))
88+
} else {
89+
Arc::new(NoopSealer)
90+
};
8091

8192
Ok(Output {
8293
sync_state,

core/node/state_keeper/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ zksync_base_token_adjuster.workspace = true
3333
zksync_node_framework.workspace = true
3434
zksync_shared_resources.workspace = true
3535
kzg.workspace = true
36-
3736
anyhow.workspace = true
3837
async-trait.workspace = true
3938
tokio = { workspace = true, features = ["time"] }

0 commit comments

Comments
 (0)