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: Use config for max number of circuits #1573

Merged
merged 7 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
6 changes: 6 additions & 0 deletions core/lib/config/src/configs/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@ pub struct StateKeeperConfig {
/// Number of keys that is processed by enum_index migration in State Keeper each L1 batch.
pub enum_index_migration_chunk_size: Option<usize>,

/// The maximal number of circuits that a batch can support.
/// Note, that this number corresponds to the "base layer" circuits, i.e. it does not include
/// the recursion layers' circuits.
pub max_circuits_per_batch: usize,

// Base system contract hashes, required only for generating genesis config.
// #PLA-811
#[deprecated(note = "Use GenesisConfig::bootloader_hash instead")]
Expand Down Expand Up @@ -199,6 +204,7 @@ impl StateKeeperConfig {
virtual_blocks_interval: 1,
virtual_blocks_per_miniblock: 1,
enum_index_migration_chunk_size: None,
max_circuits_per_batch: 24100,
bootloader_hash: None,
default_aa_hash: None,
l1_batch_commit_data_generator_mode: L1BatchCommitDataGeneratorMode::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 @@ -172,6 +172,7 @@ impl Distribution<configs::chain::StateKeeperConfig> for EncodeDist {
virtual_blocks_interval: self.sample(rng),
virtual_blocks_per_miniblock: self.sample(rng),
enum_index_migration_chunk_size: self.sample(rng),
max_circuits_per_batch: 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 @@ -105,6 +105,7 @@ mod tests {
"0x0100055b041eb28aff6e3a6e0f37c31fd053fc9ef142683b05e5f0aee6934066",
)),
l1_batch_commit_data_generator_mode,
max_circuits_per_batch: 24100,
}
}

Expand Down
20 changes: 20 additions & 0 deletions core/lib/multivm/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,23 @@ pub fn get_max_batch_gas_limit(version: VmVersion) -> u64 {
VmVersion::Vm1_4_2 => crate::vm_1_4_2::constants::BLOCK_GAS_LIMIT as u64,
}
}

pub fn get_max_batch_base_layer_circuits(version: VmVersion) -> usize {
match version {
VmVersion::M5WithRefunds
| VmVersion::M5WithoutRefunds
| VmVersion::M6Initial
| VmVersion::M6BugWithCompressionFixed
| VmVersion::Vm1_3_2
| VmVersion::VmVirtualBlocks
| VmVersion::VmVirtualBlocksRefundsEnhancement
| VmVersion::VmBoojumIntegration
| VmVersion::Vm1_4_1
| VmVersion::Vm1_4_2 => {
// For pre-v1.4.2 the maximal number of circuits has not been calculated, but since
// these are used only for replaying transactions, we'll reuse the same value as for v1.4.2.
// We avoid providing `0` for the old versions to avoid potential errors when working with old versions.
crate::vm_1_4_2::constants::MAX_BASE_LAYER_CIRCUITS
}
}
}
2 changes: 2 additions & 0 deletions core/lib/multivm/src/versions/vm_1_4_2/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ pub(crate) const BOOTLOADER_BATCH_TIP_OVERHEAD: u32 = 170_000_000;
pub(crate) const BOOTLOADER_BATCH_TIP_CIRCUIT_STATISTICS_OVERHEAD: u32 = 5000;
pub(crate) const BOOTLOADER_BATCH_TIP_METRICS_SIZE_OVERHEAD: u32 = 1500;

pub(crate) const MAX_BASE_LAYER_CIRCUITS: usize = 24100;

/// The size of the bootloader memory in bytes which is used by the protocol.
/// While the maximal possible size is a lot higher, we restrict ourselves to a certain limit to reduce
/// the requirements on RAM.
Expand Down
4 changes: 4 additions & 0 deletions core/lib/protobuf_config/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ impl ProtoRepr for proto::StateKeeper {
.map(|x| x.try_into())
.transpose()
.context("enum_index_migration_chunk_size")?,
max_circuits_per_batch: required(&self.max_circuits_per_batch)
.and_then(|x| Ok((*x).try_into()?))
.context("max_circuits_per_batch")?,

// 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 @@ -122,6 +125,7 @@ impl ProtoRepr for proto::StateKeeper {
.enum_index_migration_chunk_size
.as_ref()
.map(|x| (*x).try_into().unwrap()),
max_circuits_per_batch: Some(this.max_circuits_per_batch.try_into().unwrap()),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions core/lib/protobuf_config/src/proto/chain.proto
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ message StateKeeper {
optional uint32 virtual_blocks_interval = 23; // required
optional uint32 virtual_blocks_per_miniblock = 24; // required
optional uint64 enum_index_migration_chunk_size = 26; // optional
optional uint64 max_circuits_per_batch = 27; // required
}

message OperationsManager {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,93 +1,85 @@
use std::fmt;

use multivm::utils::circuit_statistics_bootloader_batch_tip_overhead;
use multivm::utils::{
circuit_statistics_bootloader_batch_tip_overhead, get_max_batch_base_layer_circuits,
};
use zksync_config::configs::chain::StateKeeperConfig;
use zksync_types::{tx::tx_execution_info::ExecutionMetrics, ProtocolVersionId};
use zksync_types::ProtocolVersionId;

// Local uses
use crate::state_keeper::seal_criteria::{SealCriterion, SealData, SealResolution};

// Collected vm execution metrics should fit into geometry limits.
// Otherwise witness generation will fail and proof won't be generated.

#[derive(Debug, Default)]
/// Checks whether we should exclude the transaction because we don't have enough circuits for it.
#[derive(Debug)]
pub struct CircuitsCriterion;

trait MetricExtractor {
const PROM_METRIC_CRITERION_NAME: &'static str;
fn limit_per_block(protocol_version: ProtocolVersionId) -> usize;
fn extract(metric: &ExecutionMetrics) -> usize;
}

impl<T> SealCriterion for T
where
T: MetricExtractor + fmt::Debug + Send + Sync + 'static,
{
impl SealCriterion for CircuitsCriterion {
fn should_seal(
&self,
config: &StateKeeperConfig,
_block_open_timestamp_ms: u128,
_tx_count: usize,
block_data: &SealData,
tx_data: &SealData,
protocol_version_id: ProtocolVersionId,
protocol_version: ProtocolVersionId,
) -> SealResolution {
let reject_bound = (T::limit_per_block(protocol_version_id) as f64
let max_allowed_base_layer_circuits =
get_max_batch_base_layer_circuits(protocol_version.into());
assert!(
config.max_circuits_per_batch <= max_allowed_base_layer_circuits,
"Configured max_circuits_per_batch ({}) must be lower than the bootloader constant MAX_BASE_LAYER_CIRCUITS={} for protocol version {}",
config.max_circuits_per_batch, max_allowed_base_layer_circuits, protocol_version as u16
StanislavBreadless marked this conversation as resolved.
Show resolved Hide resolved
);

let batch_tip_circuit_overhead =
circuit_statistics_bootloader_batch_tip_overhead(ProtocolVersionId::latest().into());

StanislavBreadless marked this conversation as resolved.
Show resolved Hide resolved
// Double checking that it is possible to seal batches
assert!(
batch_tip_circuit_overhead < config.max_circuits_per_batch,
"Invalid circuit criteria"
);

let reject_bound = (config.max_circuits_per_batch as f64
* config.reject_tx_at_geometry_percentage)
.round();
let close_bound = (T::limit_per_block(protocol_version_id) as f64
.round() as usize;
let include_and_seal_bound = (config.max_circuits_per_batch as f64
* config.close_block_at_geometry_percentage)
.round();
.round() as usize;

if T::extract(&tx_data.execution_metrics)
+ circuit_statistics_bootloader_batch_tip_overhead(protocol_version_id.into())
> reject_bound as usize
{
let used_circuits_tx = tx_data.execution_metrics.circuit_statistic.total();
let used_circuits_batch = block_data.execution_metrics.circuit_statistic.total();

if used_circuits_tx + batch_tip_circuit_overhead >= reject_bound {
SealResolution::Unexecutable("ZK proof cannot be generated for a transaction".into())
} else if T::extract(&block_data.execution_metrics)
+ circuit_statistics_bootloader_batch_tip_overhead(protocol_version_id.into())
>= T::limit_per_block(protocol_version_id)
} else if used_circuits_batch + batch_tip_circuit_overhead >= config.max_circuits_per_batch
{
SealResolution::ExcludeAndSeal
} else if T::extract(&block_data.execution_metrics)
+ circuit_statistics_bootloader_batch_tip_overhead(protocol_version_id.into())
> close_bound as usize
{
} else if used_circuits_batch + batch_tip_circuit_overhead >= include_and_seal_bound {
SealResolution::IncludeAndSeal
} else {
SealResolution::NoSeal
}
}

fn prom_criterion_name(&self) -> &'static str {
T::PROM_METRIC_CRITERION_NAME
}
}

impl MetricExtractor for CircuitsCriterion {
const PROM_METRIC_CRITERION_NAME: &'static str = "circuits";

fn limit_per_block(_protocol_version_id: ProtocolVersionId) -> usize {
const MAX_NUMBER_OF_CIRCUITS: usize = 24100;

MAX_NUMBER_OF_CIRCUITS
}

fn extract(metrics: &ExecutionMetrics) -> usize {
metrics.circuit_statistic.total()
"circuits_criterion"
}
}

#[cfg(test)]
mod tests {
use zksync_types::circuit::CircuitStatistic;
use zksync_types::{circuit::CircuitStatistic, tx::ExecutionMetrics};

use super::*;

const MAX_CIRCUITS_PER_BATCH: usize = 100;

fn get_config() -> StateKeeperConfig {
StateKeeperConfig {
close_block_at_geometry_percentage: 0.9,
reject_tx_at_geometry_percentage: 0.9,
max_circuits_per_batch: MAX_CIRCUITS_PER_BATCH,
..Default::default()
}
}
Expand Down Expand Up @@ -182,7 +174,7 @@ mod tests {
let protocol_version = ProtocolVersionId::latest();
let block_execution_metrics = ExecutionMetrics {
circuit_statistic: CircuitStatistic {
main_vm: (CircuitsCriterion::limit_per_block(protocol_version) / 2) as f32,
main_vm: (MAX_CIRCUITS_PER_BATCH / 2) as f32,
..CircuitStatistic::default()
},
..ExecutionMetrics::default()
Expand All @@ -195,7 +187,7 @@ mod tests {

let block_execution_metrics = ExecutionMetrics {
circuit_statistic: CircuitStatistic {
main_vm: (CircuitsCriterion::limit_per_block(protocol_version)
main_vm: (MAX_CIRCUITS_PER_BATCH
- 1
- circuit_statistics_bootloader_batch_tip_overhead(
ProtocolVersionId::latest().into(),
Expand All @@ -213,7 +205,7 @@ mod tests {

let block_execution_metrics = ExecutionMetrics {
circuit_statistic: CircuitStatistic {
main_vm: CircuitsCriterion::limit_per_block(protocol_version) as f32,
main_vm: MAX_CIRCUITS_PER_BATCH as f32,
..CircuitStatistic::default()
},
..ExecutionMetrics::default()
Expand All @@ -227,7 +219,7 @@ mod tests {

let tx_execution_metrics = ExecutionMetrics {
circuit_statistic: CircuitStatistic {
main_vm: CircuitsCriterion::limit_per_block(protocol_version) as f32
main_vm: MAX_CIRCUITS_PER_BATCH as f32
* config.reject_tx_at_geometry_percentage as f32
+ 1.0,
..CircuitStatistic::default()
Expand Down
4 changes: 4 additions & 0 deletions etc/env/base/chain.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ reject_tx_at_geometry_percentage = 0.95
# Configuration option for block to be sealed in case
# it takes more percentage of the max block capacity than this value.
reject_tx_at_eth_params_percentage = 0.95
# The maximal number of circuits that a batch can support.
# Note, that this number corresponds to the "base layer" circuits, i.e. it does not include
# the recursion layers' circuits.
max_circuits_per_batch = 24100

# Configuration option for block to be sealed in case
# it takes more percentage of the max block gas capacity than this value.
Expand Down
Loading