diff --git a/core/lib/types/src/aggregated_operations.rs b/core/lib/types/src/aggregated_operations.rs index dadfad265cb2..dc0e3e6153c7 100644 --- a/core/lib/types/src/aggregated_operations.rs +++ b/core/lib/types/src/aggregated_operations.rs @@ -39,3 +39,9 @@ impl FromStr for AggregatedActionType { } } } + +/// Additional cost of processing `Execute` operation per batch. +pub const L1_BATCH_EXECUTE_BASE_COST: u32 = 30_000; + +/// Additional cost of processing `Execute` operation per L1->L2 tx. +pub const L1_OPERATION_EXECUTE_COST: u32 = 12_500; diff --git a/core/node/eth_sender/src/publish_criterion.rs b/core/node/eth_sender/src/publish_criterion.rs index 6a38e564ed6d..36052fe5976a 100644 --- a/core/node/eth_sender/src/publish_criterion.rs +++ b/core/node/eth_sender/src/publish_criterion.rs @@ -4,7 +4,11 @@ use async_trait::async_trait; use chrono::Utc; use zksync_dal::{Connection, Core, CoreDal}; use zksync_types::{ - aggregated_operations::AggregatedActionType, commitment::L1BatchWithMetadata, L1BatchNumber, + aggregated_operations::{ + AggregatedActionType, L1_BATCH_EXECUTE_BASE_COST, L1_OPERATION_EXECUTE_COST, + }, + commitment::L1BatchWithMetadata, + L1BatchNumber, }; use super::metrics::METRICS; @@ -125,11 +129,7 @@ pub struct ExecuteGasCriterion { impl ExecuteGasCriterion { /// Base cost of processing aggregated `Execute` operation. - pub const AGGR_L1_BATCH_EXECUTE_BASE_COST: u32 = 241_000; - /// Additional cost of processing `Execute` per batch. - pub const L1_BATCH_EXECUTE_BASE_COST: u32 = 30_000; - /// Additional cost of processing `Execute` per L1->L2 tx. - pub const L1_OPERATION_EXECUTE_COST: u32 = 12_500; + const AGGR_L1_BATCH_EXECUTE_BASE_COST: u32 = 241_000; pub fn new(gas_limit: u32) -> ExecuteGasCriterion { ExecuteGasCriterion { gas_limit } @@ -159,8 +159,7 @@ impl ExecuteGasCriterion { .unwrap() .unwrap_or_else(|| panic!("Missing L1 batch header in DB for #{batch_number}")); - Self::L1_BATCH_EXECUTE_BASE_COST - + u32::from(header.l1_tx_count) * Self::L1_OPERATION_EXECUTE_COST + L1_BATCH_EXECUTE_BASE_COST + u32::from(header.l1_tx_count) * L1_OPERATION_EXECUTE_COST } } diff --git a/core/node/state_keeper/src/io/seal_logic/l2_block_seal_subtasks.rs b/core/node/state_keeper/src/io/seal_logic/l2_block_seal_subtasks.rs index 8c1730b88cf1..701e121285d4 100644 --- a/core/node/state_keeper/src/io/seal_logic/l2_block_seal_subtasks.rs +++ b/core/node/state_keeper/src/io/seal_logic/l2_block_seal_subtasks.rs @@ -541,6 +541,7 @@ mod tests { block_execution_metrics: Default::default(), txs_encoding_size: Default::default(), payload_encoding_size: Default::default(), + l1_tx_count: 0, timestamp: 1, number: L2BlockNumber(1), prev_block_hash: Default::default(), diff --git a/core/node/state_keeper/src/keeper.rs b/core/node/state_keeper/src/keeper.rs index 83b447936408..5c82aa7a180f 100644 --- a/core/node/state_keeper/src/keeper.rs +++ b/core/node/state_keeper/src/keeper.rs @@ -820,11 +820,13 @@ impl ZkSyncStateKeeper { writes_metrics: block_writes_metrics, gas_remaining: *gas_remaining, }; + let is_tx_l1 = tx.is_l1() as usize; self.sealer.should_seal_l1_batch( updates_manager.l1_batch.number.0, updates_manager.batch_timestamp() as u128 * 1_000, updates_manager.pending_executed_transactions_len() + 1, + updates_manager.pending_l1_transactions_len() + is_tx_l1, &block_data, &tx_data, updates_manager.protocol_version(), diff --git a/core/node/state_keeper/src/seal_criteria/conditional_sealer.rs b/core/node/state_keeper/src/seal_criteria/conditional_sealer.rs index bdb4a86cb794..d4ce1fec0b82 100644 --- a/core/node/state_keeper/src/seal_criteria/conditional_sealer.rs +++ b/core/node/state_keeper/src/seal_criteria/conditional_sealer.rs @@ -23,11 +23,13 @@ pub trait ConditionalSealer: 'static + fmt::Debug + Send + Sync { ) -> Option<&'static str>; /// Returns the action that should be taken by the state keeper after executing a transaction. + #[allow(clippy::too_many_arguments)] fn should_seal_l1_batch( &self, l1_batch_number: u32, block_open_timestamp_ms: u128, tx_count: usize, + l1_tx_count: usize, block_data: &SealData, tx_data: &SealData, protocol_version: ProtocolVersionId, @@ -59,6 +61,7 @@ impl ConditionalSealer for SequencerSealer { &self.config, MOCK_BLOCK_TIMESTAMP, TX_COUNT, + TX_COUNT, data, data, protocol_version, @@ -75,6 +78,7 @@ impl ConditionalSealer for SequencerSealer { l1_batch_number: u32, block_open_timestamp_ms: u128, tx_count: usize, + l1_tx_count: usize, block_data: &SealData, tx_data: &SealData, protocol_version: ProtocolVersionId, @@ -91,6 +95,7 @@ impl ConditionalSealer for SequencerSealer { &self.config, block_open_timestamp_ms, tx_count, + l1_tx_count, block_data, tx_data, protocol_version, @@ -138,6 +143,7 @@ impl SequencerSealer { Box::new(criteria::CircuitsCriterion), Box::new(criteria::TxEncodingSizeCriterion), Box::new(criteria::GasForBatchTipCriterion), + Box::new(criteria::L1L2TxsCriterion), ] } } @@ -162,6 +168,7 @@ impl ConditionalSealer for NoopSealer { _l1_batch_number: u32, _block_open_timestamp_ms: u128, _tx_count: usize, + _l1_tx_count: usize, _block_data: &SealData, _tx_data: &SealData, _protocol_version: ProtocolVersionId, diff --git a/core/node/state_keeper/src/seal_criteria/criteria/gas_for_batch_tip.rs b/core/node/state_keeper/src/seal_criteria/criteria/gas_for_batch_tip.rs index 69214406bea5..263123cdcff2 100644 --- a/core/node/state_keeper/src/seal_criteria/criteria/gas_for_batch_tip.rs +++ b/core/node/state_keeper/src/seal_criteria/criteria/gas_for_batch_tip.rs @@ -15,6 +15,7 @@ impl SealCriterion for GasForBatchTipCriterion { _config: &StateKeeperConfig, _block_open_timestamp_ms: u128, tx_count: usize, + _l1_tx_count: usize, _block_data: &SealData, tx_data: &SealData, protocol_version: ProtocolVersionId, @@ -60,6 +61,7 @@ mod tests { &config, Default::default(), 1, + 0, &seal_data, &seal_data, protocol_version, @@ -74,6 +76,7 @@ mod tests { &config, Default::default(), 1, + 0, &seal_data, &seal_data, protocol_version, @@ -87,6 +90,7 @@ mod tests { &config, Default::default(), 2, + 0, &seal_data, &seal_data, protocol_version, diff --git a/core/node/state_keeper/src/seal_criteria/criteria/geometry_seal_criteria.rs b/core/node/state_keeper/src/seal_criteria/criteria/geometry_seal_criteria.rs index 1f3e8d104ce5..657fa1f71800 100644 --- a/core/node/state_keeper/src/seal_criteria/criteria/geometry_seal_criteria.rs +++ b/core/node/state_keeper/src/seal_criteria/criteria/geometry_seal_criteria.rs @@ -20,6 +20,7 @@ impl SealCriterion for CircuitsCriterion { config: &StateKeeperConfig, _block_open_timestamp_ms: u128, _tx_count: usize, + _l1_tx_count: usize, block_data: &SealData, tx_data: &SealData, protocol_version: ProtocolVersionId, @@ -94,6 +95,7 @@ mod tests { &config, Default::default(), 0, + 0, &SealData { execution_metrics: block_execution_metrics, ..SealData::default() @@ -114,6 +116,7 @@ mod tests { &config, Default::default(), 0, + 0, &SealData { execution_metrics: block_execution_metrics, ..SealData::default() @@ -134,6 +137,7 @@ mod tests { &config, Default::default(), 0, + 0, &SealData { execution_metrics: block_execution_metrics, ..SealData::default() @@ -154,6 +158,7 @@ mod tests { &config, Default::default(), 0, + 0, &SealData::default(), &SealData { execution_metrics: tx_execution_metrics, diff --git a/core/node/state_keeper/src/seal_criteria/criteria/l1_l2_txs.rs b/core/node/state_keeper/src/seal_criteria/criteria/l1_l2_txs.rs new file mode 100644 index 000000000000..abf1d6f993a9 --- /dev/null +++ b/core/node/state_keeper/src/seal_criteria/criteria/l1_l2_txs.rs @@ -0,0 +1,96 @@ +use zksync_types::{ + aggregated_operations::{L1_BATCH_EXECUTE_BASE_COST, L1_OPERATION_EXECUTE_COST}, + ProtocolVersionId, +}; + +use crate::seal_criteria::{SealCriterion, SealData, SealResolution, StateKeeperConfig}; + +#[derive(Debug)] +pub(crate) struct L1L2TxsCriterion; + +impl SealCriterion for L1L2TxsCriterion { + fn should_seal( + &self, + config: &StateKeeperConfig, + _block_open_timestamp_ms: u128, + _tx_count: usize, + l1_tx_count: usize, + _block_data: &SealData, + _tx_data: &SealData, + _protocol_version_id: ProtocolVersionId, + ) -> SealResolution { + let block_l1_gas_bound = + (config.max_single_tx_gas as f64 * config.close_block_at_gas_percentage).round() as u32; + let l1_gas = L1_BATCH_EXECUTE_BASE_COST + (l1_tx_count as u32) * L1_OPERATION_EXECUTE_COST; + + if l1_gas >= block_l1_gas_bound { + SealResolution::IncludeAndSeal + } else { + SealResolution::NoSeal + } + } + + fn prom_criterion_name(&self) -> &'static str { + "gas" + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_l1_l2_txs_seal_criterion() { + let max_single_tx_gas = 15_000_000; + let close_block_at_gas_percentage = 0.95; + + let gas_bound = (max_single_tx_gas as f64 * close_block_at_gas_percentage).round() as u32; + let l1_tx_count_bound = + (gas_bound - L1_BATCH_EXECUTE_BASE_COST - 1) / L1_OPERATION_EXECUTE_COST; + + // Create an empty config and only setup fields relevant for the test. + let config = StateKeeperConfig { + max_single_tx_gas, + close_block_at_gas_percentage, + ..Default::default() + }; + + let criterion = L1L2TxsCriterion; + + // Empty block should fit into gas criterion. + let empty_block_resolution = criterion.should_seal( + &config, + 0, + 0, + 0, + &SealData::default(), + &SealData::default(), + ProtocolVersionId::latest(), + ); + assert_eq!(empty_block_resolution, SealResolution::NoSeal); + + // `l1_tx_count_bound` should return `NoSeal`. + let block_resolution = criterion.should_seal( + &config, + 0, + 0, + l1_tx_count_bound as usize, + &SealData::default(), + &SealData::default(), + ProtocolVersionId::latest(), + ); + assert_eq!(block_resolution, SealResolution::NoSeal); + + // `l1_tx_count_bound + 1` should return `IncludeAndSeal`. + let block_resolution = criterion.should_seal( + &config, + 0, + 0, + l1_tx_count_bound as usize + 1, + &SealData::default(), + &SealData::default(), + ProtocolVersionId::latest(), + ); + assert_eq!(block_resolution, SealResolution::IncludeAndSeal); + } +} diff --git a/core/node/state_keeper/src/seal_criteria/criteria/mod.rs b/core/node/state_keeper/src/seal_criteria/criteria/mod.rs index 662efa1485b6..3914acfda889 100644 --- a/core/node/state_keeper/src/seal_criteria/criteria/mod.rs +++ b/core/node/state_keeper/src/seal_criteria/criteria/mod.rs @@ -1,11 +1,12 @@ mod gas_for_batch_tip; mod geometry_seal_criteria; +mod l1_l2_txs; mod pubdata_bytes; mod slots; mod tx_encoding_size; pub(crate) use self::{ gas_for_batch_tip::GasForBatchTipCriterion, geometry_seal_criteria::CircuitsCriterion, - pubdata_bytes::PubDataBytesCriterion, slots::SlotsCriterion, + l1_l2_txs::L1L2TxsCriterion, pubdata_bytes::PubDataBytesCriterion, slots::SlotsCriterion, tx_encoding_size::TxEncodingSizeCriterion, }; diff --git a/core/node/state_keeper/src/seal_criteria/criteria/pubdata_bytes.rs b/core/node/state_keeper/src/seal_criteria/criteria/pubdata_bytes.rs index 09fcf2f0fc1b..5cddfffd6899 100644 --- a/core/node/state_keeper/src/seal_criteria/criteria/pubdata_bytes.rs +++ b/core/node/state_keeper/src/seal_criteria/criteria/pubdata_bytes.rs @@ -20,6 +20,7 @@ impl SealCriterion for PubDataBytesCriterion { config: &StateKeeperConfig, _block_open_timestamp_ms: u128, _tx_count: usize, + _l1_tx_count: usize, block_data: &SealData, tx_data: &SealData, protocol_version: ProtocolVersionId, @@ -99,6 +100,7 @@ mod tests { &config, 0, 0, + 0, &SealData { execution_metrics: block_execution_metrics, ..SealData::default() @@ -120,6 +122,7 @@ mod tests { &config, 0, 0, + 0, &SealData { execution_metrics: block_execution_metrics, ..SealData::default() @@ -137,6 +140,7 @@ mod tests { &config, 0, 0, + 0, &SealData { execution_metrics: block_execution_metrics, ..SealData::default() diff --git a/core/node/state_keeper/src/seal_criteria/criteria/slots.rs b/core/node/state_keeper/src/seal_criteria/criteria/slots.rs index 81b3a0933801..ad07bf8f8a00 100644 --- a/core/node/state_keeper/src/seal_criteria/criteria/slots.rs +++ b/core/node/state_keeper/src/seal_criteria/criteria/slots.rs @@ -13,6 +13,7 @@ impl SealCriterion for SlotsCriterion { config: &StateKeeperConfig, _block_open_timestamp_ms: u128, tx_count: usize, + _l1_tx_count: usize, _block_data: &SealData, _tx_data: &SealData, protocol_version: ProtocolVersionId, @@ -54,6 +55,7 @@ mod tests { &config, Default::default(), config.transaction_slots - 1, + 0, &SealData::default(), &SealData::default(), ProtocolVersionId::latest(), @@ -64,6 +66,7 @@ mod tests { &config, Default::default(), config.transaction_slots, + 0, &SealData::default(), &SealData::default(), ProtocolVersionId::latest(), diff --git a/core/node/state_keeper/src/seal_criteria/criteria/tx_encoding_size.rs b/core/node/state_keeper/src/seal_criteria/criteria/tx_encoding_size.rs index 409673d6cac8..54076dc8ccc0 100644 --- a/core/node/state_keeper/src/seal_criteria/criteria/tx_encoding_size.rs +++ b/core/node/state_keeper/src/seal_criteria/criteria/tx_encoding_size.rs @@ -14,6 +14,7 @@ impl SealCriterion for TxEncodingSizeCriterion { config: &StateKeeperConfig, _block_open_timestamp_ms: u128, _tx_count: usize, + _l1_tx_count: usize, block_data: &SealData, tx_data: &SealData, protocol_version_id: ProtocolVersionId, @@ -65,6 +66,7 @@ mod tests { &config, 0, 0, + 0, &SealData::default(), &SealData::default(), ProtocolVersionId::latest(), @@ -75,6 +77,7 @@ mod tests { &config, 0, 0, + 0, &SealData::default(), &SealData { cumulative_size: bootloader_tx_encoding_space as usize + 1, @@ -91,6 +94,7 @@ mod tests { &config, 0, 0, + 0, &SealData { cumulative_size: bootloader_tx_encoding_space as usize + 1, ..SealData::default() @@ -107,6 +111,7 @@ mod tests { &config, 0, 0, + 0, &SealData { cumulative_size: bootloader_tx_encoding_space as usize, ..SealData::default() diff --git a/core/node/state_keeper/src/seal_criteria/mod.rs b/core/node/state_keeper/src/seal_criteria/mod.rs index 85b805a98283..6a1bde448474 100644 --- a/core/node/state_keeper/src/seal_criteria/mod.rs +++ b/core/node/state_keeper/src/seal_criteria/mod.rs @@ -177,11 +177,13 @@ impl SealData { } pub(super) trait SealCriterion: fmt::Debug + Send + Sync + 'static { + #[allow(clippy::too_many_arguments)] fn should_seal( &self, config: &StateKeeperConfig, block_open_timestamp_ms: u128, tx_count: usize, + l1_tx_count: usize, block_data: &SealData, tx_data: &SealData, protocol_version: ProtocolVersionId, diff --git a/core/node/state_keeper/src/updates/l1_batch_updates.rs b/core/node/state_keeper/src/updates/l1_batch_updates.rs index fc0aa555934a..f7a93b4870b9 100644 --- a/core/node/state_keeper/src/updates/l1_batch_updates.rs +++ b/core/node/state_keeper/src/updates/l1_batch_updates.rs @@ -12,6 +12,7 @@ pub struct L1BatchUpdates { pub priority_ops_onchain_data: Vec, pub block_execution_metrics: VmExecutionMetrics, pub txs_encoding_size: usize, + pub l1_tx_count: usize, pub finished: Option, } @@ -23,6 +24,7 @@ impl L1BatchUpdates { priority_ops_onchain_data: Default::default(), block_execution_metrics: Default::default(), txs_encoding_size: 0, + l1_tx_count: 0, finished: None, } } @@ -39,6 +41,7 @@ impl L1BatchUpdates { self.block_execution_metrics += l2_block_updates.block_execution_metrics; self.txs_encoding_size += l2_block_updates.txs_encoding_size; + self.l1_tx_count += l2_block_updates.l1_tx_count; } } @@ -80,5 +83,6 @@ mod tests { 0 ); assert_eq!(l1_batch_accumulator.txs_encoding_size, expected_tx_size); + assert_eq!(l1_batch_accumulator.l1_tx_count, 0); } } diff --git a/core/node/state_keeper/src/updates/l2_block_updates.rs b/core/node/state_keeper/src/updates/l2_block_updates.rs index 4130e9e1ea5e..628f9e4a2910 100644 --- a/core/node/state_keeper/src/updates/l2_block_updates.rs +++ b/core/node/state_keeper/src/updates/l2_block_updates.rs @@ -27,6 +27,7 @@ pub struct L2BlockUpdates { pub block_execution_metrics: VmExecutionMetrics, pub txs_encoding_size: usize, pub payload_encoding_size: usize, + pub l1_tx_count: usize, pub timestamp: u64, pub number: L2BlockNumber, pub prev_block_hash: H256, @@ -52,6 +53,7 @@ impl L2BlockUpdates { block_execution_metrics: VmExecutionMetrics::default(), txs_encoding_size: 0, payload_encoding_size: 0, + l1_tx_count: 0, timestamp, number, prev_block_hash, @@ -148,6 +150,9 @@ impl L2BlockUpdates { .extend(tx_execution_result.logs.system_l2_to_l1_logs); self.storage_logs .extend(tx_execution_result.logs.storage_logs); + if tx.is_l1() { + self.l1_tx_count += 1; + } self.executed_transactions.push(TransactionExecutionResult { hash: tx.hash(), @@ -219,5 +224,6 @@ mod tests { assert_eq!(accumulator.block_execution_metrics.l2_to_l1_logs, 0); assert_eq!(accumulator.txs_encoding_size, bootloader_encoding_size); assert_eq!(accumulator.payload_encoding_size, payload_encoding_size); + assert_eq!(accumulator.l1_tx_count, 0); } } diff --git a/core/node/state_keeper/src/updates/mod.rs b/core/node/state_keeper/src/updates/mod.rs index 32e23b73229a..06ac4bcd5de0 100644 --- a/core/node/state_keeper/src/updates/mod.rs +++ b/core/node/state_keeper/src/updates/mod.rs @@ -184,6 +184,10 @@ impl UpdatesManager { self.l1_batch.executed_transactions.len() + self.l2_block.executed_transactions.len() } + pub(crate) fn pending_l1_transactions_len(&self) -> usize { + self.l1_batch.l1_tx_count + self.l2_block.l1_tx_count + } + pub(crate) fn pending_execution_metrics(&self) -> VmExecutionMetrics { self.l1_batch.block_execution_metrics + self.l2_block.block_execution_metrics } diff --git a/etc/env/file_based/general.yaml b/etc/env/file_based/general.yaml index a4005e9477a8..e726192b980d 100644 --- a/etc/env/file_based/general.yaml +++ b/etc/env/file_based/general.yaml @@ -101,7 +101,6 @@ eth: aggregated_block_execute_deadline: 10 timestamp_criteria_max_allowed_lag: 30 max_eth_tx_data_size: 120000 - aggregated_proof_sizes: [ 1 ] max_aggregated_tx_gas: 15000000 max_acceptable_priority_fee_in_gwei: 100000000000 # typo: value is in wei (100 gwei) pubdata_sending_mode: BLOBS