Skip to content

Commit

Permalink
feat: Remove batch dry_run (#1076)
Browse files Browse the repository at this point in the history
## What ❔

Remove `batch_dry_run` method
Hardcode values needed for seal criterions

## Why ❔

`batch_dry_run` is not needed anymore

## Checklist

<!-- Check your PR fulfills the following items. -->
<!-- For draft PRs check the boxes as you complete them. -->

- [x] PR title corresponds to the body of PR (we generate changelog
entries from PRs).
- [x] Tests for the changes have been added / updated.
- [x] Documentation comments have been added / updated.
- [x] Code has been formatted via `zk fmt` and `zk lint`.
- [x] Spellcheck has been run via `zk spellcheck`.
- [x] Linkcheck has been run via `zk linkcheck`.
  • Loading branch information
Artemka374 committed Mar 20, 2024
1 parent c072288 commit b82d093
Show file tree
Hide file tree
Showing 12 changed files with 99 additions and 149 deletions.
40 changes: 40 additions & 0 deletions core/lib/multivm/src/utils.rs
Expand Up @@ -260,6 +260,46 @@ pub fn gas_bootloader_batch_tip_overhead(version: VmVersion) -> u32 {
}
}

pub fn circuit_statistics_bootloader_batch_tip_overhead(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 => {
// For these versions the overhead has not been calculated and it has not been used with those versions.
0
}
VmVersion::Vm1_4_2 => {
crate::vm_latest::constants::BOOTLOADER_BATCH_TIP_CIRCUIT_STATISTICS_OVERHEAD as usize
}
}
}

pub fn execution_metrics_bootloader_batch_tip_overhead(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 => {
// For these versions the overhead has not been calculated and it has not been used with those versions.
0
}
VmVersion::Vm1_4_2 => {
crate::vm_latest::constants::BOOTLOADER_BATCH_TIP_METRICS_SIZE_OVERHEAD as usize
}
}
}

pub fn get_max_gas_per_pubdata_byte(version: VmVersion) -> u64 {
match version {
VmVersion::M5WithRefunds | VmVersion::M5WithoutRefunds => {
Expand Down
6 changes: 2 additions & 4 deletions core/lib/multivm/src/versions/vm_latest/constants.rs
Expand Up @@ -10,10 +10,8 @@ use crate::vm_latest::old_vm::utils::heap_page_from_base;
/// The amount of ergs to be reserved at the end of the batch to ensure that it has enough ergs to verify compression, etc.
pub(crate) const BOOTLOADER_BATCH_TIP_OVERHEAD: u32 = 170_000_000;

#[allow(dead_code)]
pub(crate) const BOOTLOADER_BATCH_TIP_CIRCUIT_STATISTICS_OVERHEAD: u64 = 5000;
#[allow(dead_code)]
pub(crate) const BOOTLOADER_BATCH_TIP_METRICS_SIZE_OVERHEAD: u64 = 1500;
pub(crate) const BOOTLOADER_BATCH_TIP_CIRCUIT_STATISTICS_OVERHEAD: u32 = 5000;
pub(crate) const BOOTLOADER_BATCH_TIP_METRICS_SIZE_OVERHEAD: u32 = 1500;

/// 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
Expand Down
4 changes: 2 additions & 2 deletions core/lib/multivm/src/versions/vm_latest/tests/block_tip.rs
Expand Up @@ -374,7 +374,7 @@ fn test_dry_run_upper_bound() {
.max()
.unwrap();
assert!(
circuit_statistics.0 * 2 <= BOOTLOADER_BATCH_TIP_CIRCUIT_STATISTICS_OVERHEAD,
circuit_statistics.0 * 2 <= BOOTLOADER_BATCH_TIP_CIRCUIT_STATISTICS_OVERHEAD as u64,
"BOOTLOADER_BATCH_TIP_CIRCUIT_STATISTICS_OVERHEAD is too low for {} with result {}, BOOTLOADER_BATCH_TIP_CIRCUIT_STATISTICS_OVERHEAD = {}",
circuit_statistics.1,
circuit_statistics.0,
Expand All @@ -387,7 +387,7 @@ fn test_dry_run_upper_bound() {
.max()
.unwrap();
assert!(
execution_metrics_size.0 * 2 <= BOOTLOADER_BATCH_TIP_METRICS_SIZE_OVERHEAD,
execution_metrics_size.0 * 2 <= BOOTLOADER_BATCH_TIP_METRICS_SIZE_OVERHEAD as u64,
"BOOTLOADER_BATCH_TIP_METRICS_SIZE_OVERHEAD is too low for {} with result {}, BOOTLOADER_BATCH_TIP_METRICS_SIZE_OVERHEAD = {}",
execution_metrics_size.1,
execution_metrics_size.0,
Expand Down
Expand Up @@ -3,7 +3,7 @@ use std::sync::Arc;
use async_trait::async_trait;
use multivm::{
interface::{
ExecutionResult, FinishedL1Batch, Halt, L1BatchEnv, L2BlockEnv, SystemEnv, VmExecutionMode,
ExecutionResult, FinishedL1Batch, Halt, L1BatchEnv, L2BlockEnv, SystemEnv,
VmExecutionResultAndLogs, VmInterface, VmInterfaceHistoryEnabled,
},
tracers::CallTracer,
Expand Down Expand Up @@ -215,28 +215,12 @@ impl CommandReceiver {
let tx_metrics = ExecutionMetricsForCriteria::new(Some(tx), &tx_result);
let gas_remaining = vm.gas_remaining();

let (bootloader_dry_run_result, bootloader_dry_run_metrics) = self.dryrun_block_tip(vm);
match &bootloader_dry_run_result.result {
ExecutionResult::Success { .. } => TxExecutionResult::Success {
tx_result: Box::new(tx_result),
tx_metrics: Box::new(tx_metrics),
bootloader_dry_run_metrics: Box::new(bootloader_dry_run_metrics),
bootloader_dry_run_result: Box::new(bootloader_dry_run_result),
compressed_bytecodes,
call_tracer_result,
gas_remaining,
},
ExecutionResult::Revert { .. } => {
unreachable!(
"VM must not revert when finalizing block (except `BootloaderOutOfGas`)"
);
}
ExecutionResult::Halt { reason } => match reason {
Halt::BootloaderOutOfGas => TxExecutionResult::BootloaderOutOfGasForBlockTip,
_ => {
panic!("VM must not revert when finalizing block (except `BootloaderOutOfGas`). Reason: {:#?}", reason)
}
},
TxExecutionResult::Success {
tx_result: Box::new(tx_result),
tx_metrics: Box::new(tx_metrics),
compressed_bytecodes,
call_tracer_result,
gas_remaining,
}
}

Expand Down Expand Up @@ -375,36 +359,4 @@ impl CommandReceiver {
(result, Default::default(), Default::default())
}
}

fn dryrun_block_tip<S: WriteStorage>(
&self,
vm: &mut VmInstance<S, HistoryEnabled>,
) -> (VmExecutionResultAndLogs, ExecutionMetricsForCriteria) {
let total_latency =
KEEPER_METRICS.tx_execution_time[&TxExecutionStage::DryRunRollback].start();
let stage_latency =
KEEPER_METRICS.tx_execution_time[&TxExecutionStage::DryRunMakeSnapshot].start();
// Save pre-`execute_till_block_end` VM snapshot.
vm.make_snapshot();
stage_latency.observe();

let stage_latency =
KEEPER_METRICS.tx_execution_time[&TxExecutionStage::DryRunExecuteBlockTip].start();
let block_tip_result = vm.execute(VmExecutionMode::Bootloader);
stage_latency.observe();

let stage_latency =
KEEPER_METRICS.tx_execution_time[&TxExecutionStage::DryRunGetExecutionMetrics].start();
let metrics = ExecutionMetricsForCriteria::new(None, &block_tip_result);
stage_latency.observe();

let stage_latency = KEEPER_METRICS.tx_execution_time
[&TxExecutionStage::DryRunRollbackToLatestSnapshot]
.start();
// Rollback to the pre-`execute_till_block_end` state.
vm.rollback_to_the_latest_snapshot();
stage_latency.observe();
total_latency.observe();
(block_tip_result, metrics)
}
}
8 changes: 1 addition & 7 deletions core/lib/zksync_core/src/state_keeper/batch_executor/mod.rs
Expand Up @@ -28,8 +28,6 @@ pub(crate) enum TxExecutionResult {
Success {
tx_result: Box<VmExecutionResultAndLogs>,
tx_metrics: Box<ExecutionMetricsForCriteria>,
bootloader_dry_run_metrics: Box<ExecutionMetricsForCriteria>,
bootloader_dry_run_result: Box<VmExecutionResultAndLogs>,
compressed_bytecodes: Vec<CompressedBytecodeInfo>,
call_tracer_result: Vec<Call>,
gas_remaining: u32,
Expand All @@ -38,8 +36,6 @@ pub(crate) enum TxExecutionResult {
RejectedByVm { reason: Halt },
/// Bootloader gas limit is not enough to execute the tx.
BootloaderOutOfGasForTx,
/// Bootloader gas limit is enough to run the tx but not enough to execute block tip.
BootloaderOutOfGasForBlockTip,
}

impl TxExecutionResult {
Expand All @@ -50,9 +46,7 @@ impl TxExecutionResult {
Self::RejectedByVm {
reason: rejection_reason,
} => Some(rejection_reason),
Self::BootloaderOutOfGasForTx | Self::BootloaderOutOfGasForBlockTip { .. } => {
Some(&Halt::BootloaderOutOfGas)
}
Self::BootloaderOutOfGasForTx => Some(&Halt::BootloaderOutOfGas),
}
}
}
Expand Down
35 changes: 5 additions & 30 deletions core/lib/zksync_core/src/state_keeper/keeper.rs
Expand Up @@ -24,10 +24,7 @@ use super::{
types::ExecutionMetricsForCriteria,
updates::UpdatesManager,
};
use crate::{
gas_tracker::gas_count_from_writes,
state_keeper::{io::fee_address_migration, metrics::BATCH_TIP_METRICS},
};
use crate::{gas_tracker::gas_count_from_writes, state_keeper::io::fee_address_migration};

/// Amount of time to block on waiting for some resource. The exact value is not really important,
/// we only need it to not block on waiting indefinitely and be able to process cancellation requests.
Expand Down Expand Up @@ -622,10 +619,9 @@ impl ZkSyncStateKeeper {
tx: Transaction,
) -> (SealResolution, TxExecutionResult) {
let exec_result = batch_executor.execute_tx(tx.clone()).await;
// All of `TxExecutionResult::BootloaderOutOfGasForTx`, `TxExecutionResult::BootloaderOutOfGasForBlockTip`,
// All of `TxExecutionResult::BootloaderOutOfGasForTx`,
// `Halt::NotEnoughGasProvided` correspond to out-of-gas errors but of different nature.
// - `BootloaderOutOfGasForTx`: it is returned when bootloader stack frame run out of gas before tx execution finished.
// - `BootloaderOutOfGasForBlockTip`: it is returned when bootloader stack frame run out of gas during batch tip dry run.
// - `Halt::NotEnoughGasProvided`: there are checks in bootloader in some places (search for `checkEnoughGas` calls).
// They check if there is more gas in the frame than bootloader estimates it will need.
// This error is returned when such a check fails. Basically, bootloader doesn't continue execution but panics prematurely instead.
Expand All @@ -635,15 +631,11 @@ impl ZkSyncStateKeeper {
let is_first_tx = updates_manager.pending_executed_transactions_len() == 0;
let resolution = match &exec_result {
TxExecutionResult::BootloaderOutOfGasForTx
| TxExecutionResult::BootloaderOutOfGasForBlockTip
| TxExecutionResult::RejectedByVm {
reason: Halt::NotEnoughGasProvided,
} => {
let error_message = match &exec_result {
TxExecutionResult::BootloaderOutOfGasForTx => "bootloader_tx_out_of_gas",
TxExecutionResult::BootloaderOutOfGasForBlockTip => {
"bootloader_batch_tip_out_of_gas"
}
TxExecutionResult::RejectedByVm {
reason: Halt::NotEnoughGasProvided,
} => "not_enough_gas_provided_to_start_tx",
Expand All @@ -663,8 +655,6 @@ impl ZkSyncStateKeeper {
TxExecutionResult::Success {
tx_result,
tx_metrics,
bootloader_dry_run_metrics,
bootloader_dry_run_result,
gas_remaining,
..
} => {
Expand Down Expand Up @@ -692,28 +682,13 @@ impl ZkSyncStateKeeper {
updates_manager.pending_execution_metrics() + tx_execution_metrics,
);

let ExecutionMetricsForCriteria {
l1_gas: finish_block_l1_gas,
execution_metrics: finish_block_execution_metrics,
} = **bootloader_dry_run_metrics;

let encoding_len = tx.encoding_len();

let logs_to_apply_iter = tx_result
.logs
.storage_logs
.iter()
.chain(&bootloader_dry_run_result.logs.storage_logs);
let logs_to_apply_iter = tx_result.logs.storage_logs.iter();
let block_writes_metrics = updates_manager
.storage_writes_deduplicator
.apply_and_rollback(logs_to_apply_iter.clone());

BATCH_TIP_METRICS.observe_writes_metrics(
&updates_manager.storage_writes_deduplicator.metrics(),
&block_writes_metrics,
updates_manager.protocol_version(),
);

let block_writes_l1_gas = gas_count_from_writes(
&block_writes_metrics,
updates_manager.protocol_version(),
Expand All @@ -723,10 +698,10 @@ impl ZkSyncStateKeeper {
StorageWritesDeduplicator::apply_on_empty_state(logs_to_apply_iter);
let tx_writes_l1_gas =
gas_count_from_writes(&tx_writes_metrics, updates_manager.protocol_version());
let tx_gas_excluding_writes = tx_l1_gas_this_tx + finish_block_l1_gas;
let tx_gas_excluding_writes = tx_l1_gas_this_tx;

let tx_data = SealData {
execution_metrics: tx_execution_metrics + finish_block_execution_metrics,
execution_metrics: tx_execution_metrics,
gas_count: tx_gas_excluding_writes + tx_writes_l1_gas,
cumulative_size: encoding_len,
writes_metrics: tx_writes_metrics,
Expand Down
10 changes: 0 additions & 10 deletions core/lib/zksync_core/src/state_keeper/metrics.rs
Expand Up @@ -21,16 +21,6 @@ use crate::metrics::InteractionType;
pub(crate) enum TxExecutionStage {
Execution,
TxRollback,
#[metrics(name = "dryrun_make_snapshot")]
DryRunMakeSnapshot,
#[metrics(name = "dryrun_execute_block_tip")]
DryRunExecuteBlockTip,
#[metrics(name = "dryrun_get_execution_metrics")]
DryRunGetExecutionMetrics,
#[metrics(name = "dryrun_rollback_to_the_latest_snapshot")]
DryRunRollbackToLatestSnapshot,
#[metrics(name = "dryrun_rollback")]
DryRunRollback,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelValue, EncodeLabelSet)]
Expand Down
@@ -1,5 +1,6 @@
use std::fmt;

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

Expand Down Expand Up @@ -38,13 +39,20 @@ where
* config.close_block_at_geometry_percentage)
.round();

if T::extract(&tx_data.execution_metrics) > reject_bound as usize {
if T::extract(&tx_data.execution_metrics)
+ circuit_statistics_bootloader_batch_tip_overhead(protocol_version_id.into())
> reject_bound as usize
{
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)
{
SealResolution::ExcludeAndSeal
} else if T::extract(&block_data.execution_metrics) > close_bound as usize {
} else if T::extract(&block_data.execution_metrics)
+ circuit_statistics_bootloader_batch_tip_overhead(protocol_version_id.into())
> close_bound as usize
{
SealResolution::IncludeAndSeal
} else {
SealResolution::NoSeal
Expand All @@ -60,11 +68,7 @@ impl MetricExtractor for CircuitsCriterion {
const PROM_METRIC_CRITERION_NAME: &'static str = "circuits";

fn limit_per_block(_protocol_version_id: ProtocolVersionId) -> usize {
// We subtract constant to take into account that circuits may be not fully filled.
// This constant should be greater than number of circuits types
// but we keep it larger to be on the safe side.
const MARGIN_NUMBER_OF_CIRCUITS: usize = 10000;
const MAX_NUMBER_OF_CIRCUITS: usize = (1 << 14) + (1 << 13) - MARGIN_NUMBER_OF_CIRCUITS;
const MAX_NUMBER_OF_CIRCUITS: usize = 24100;

MAX_NUMBER_OF_CIRCUITS
}
Expand Down Expand Up @@ -191,7 +195,11 @@ mod tests {

let block_execution_metrics = ExecutionMetrics {
circuit_statistic: CircuitStatistic {
main_vm: (CircuitsCriterion::limit_per_block(protocol_version) - 1) as f32,
main_vm: (CircuitsCriterion::limit_per_block(protocol_version)
- 1
- circuit_statistics_bootloader_batch_tip_overhead(
ProtocolVersionId::latest().into(),
)) as f32,
..CircuitStatistic::default()
},
..ExecutionMetrics::default()
Expand Down
@@ -1,3 +1,4 @@
use multivm::utils::execution_metrics_bootloader_batch_tip_overhead;
use zksync_types::ProtocolVersionId;

use crate::state_keeper::seal_criteria::{
Expand Down Expand Up @@ -39,12 +40,20 @@ impl SealCriterion for PubDataBytesCriterion {
} else {
tx_data.execution_metrics.pubdata_published as usize
};
if tx_size > reject_bound as usize {
if tx_size + execution_metrics_bootloader_batch_tip_overhead(protocol_version.into())
> reject_bound as usize
{
let message = "Transaction cannot be sent to L1 due to pubdata limits";
SealResolution::Unexecutable(message.into())
} else if block_size > max_pubdata_per_l1_batch {
} else if block_size
+ execution_metrics_bootloader_batch_tip_overhead(protocol_version.into())
> max_pubdata_per_l1_batch
{
SealResolution::ExcludeAndSeal
} else if block_size > include_and_seal_bound as usize {
} else if block_size
+ execution_metrics_bootloader_batch_tip_overhead(protocol_version.into())
> include_and_seal_bound as usize
{
SealResolution::IncludeAndSeal
} else {
SealResolution::NoSeal
Expand Down Expand Up @@ -79,7 +88,10 @@ mod tests {
let block_execution_metrics = ExecutionMetrics {
l2_l1_long_messages: (config.max_pubdata_per_batch as f64
* config.close_block_at_eth_params_percentage
- 1.0)
- 1.0
- execution_metrics_bootloader_batch_tip_overhead(
ProtocolVersionId::latest().into(),
) as f64)
.round() as usize,
..ExecutionMetrics::default()
};
Expand Down

0 comments on commit b82d093

Please sign in to comment.