diff --git a/core/lib/commitment_utils/src/lib.rs b/core/lib/commitment_utils/src/lib.rs index cfdfa23e81d5..c420233369f4 100644 --- a/core/lib/commitment_utils/src/lib.rs +++ b/core/lib/commitment_utils/src/lib.rs @@ -24,7 +24,7 @@ pub fn events_queue_commitment( .collect(), ), )), - VmVersion::Vm1_4_1 => Some(H256( + VmVersion::Vm1_4_1 | VmVersion::Vm1_4_2 => Some(H256( zkevm_test_harness_1_4_1::witness::utils::events_queue_commitment_fixed( &events_queue .iter() @@ -55,7 +55,7 @@ pub fn bootloader_initial_content_commitment( &full_bootloader_memory, ), )), - VmVersion::Vm1_4_1 => Some(H256( + VmVersion::Vm1_4_1 | VmVersion::Vm1_4_2 => Some(H256( zkevm_test_harness_1_4_1::witness::utils::initial_heap_content_commitment_fixed( &full_bootloader_memory, ), diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index 065008d5dbce..fe390b4cd9e2 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -312,6 +312,13 @@ impl BaseSystemContracts { BaseSystemContracts::load_with_bootloader(bootloader_bytecode) } + pub fn playground_post_1_4_2() -> Self { + let bootloader_bytecode = read_zbin_bytecode( + "etc/multivm_bootloaders/vm_1_4_2/playground_batch.yul/playground_batch.yul.zbin", + ); + BaseSystemContracts::load_with_bootloader(bootloader_bytecode) + } + pub fn estimate_gas_pre_virtual_blocks() -> Self { let bootloader_bytecode = read_zbin_bytecode( "etc/multivm_bootloaders/vm_1_3_2/fee_estimate.yul/fee_estimate.yul.zbin", @@ -354,6 +361,13 @@ impl BaseSystemContracts { BaseSystemContracts::load_with_bootloader(bootloader_bytecode) } + pub fn estimate_gas_post_1_4_2() -> Self { + let bootloader_bytecode = read_zbin_bytecode( + "etc/multivm_bootloaders/vm_1_4_2/fee_estimate.yul/fee_estimate.yul.zbin", + ); + BaseSystemContracts::load_with_bootloader(bootloader_bytecode) + } + pub fn hashes(&self) -> BaseSystemContractsHashes { BaseSystemContractsHashes { bootloader: self.bootloader.hash, diff --git a/core/lib/multivm/src/glue/history_mode.rs b/core/lib/multivm/src/glue/history_mode.rs index f820477c10a5..45de90fc446d 100644 --- a/core/lib/multivm/src/glue/history_mode.rs +++ b/core/lib/multivm/src/glue/history_mode.rs @@ -8,13 +8,15 @@ pub trait HistoryMode: + GlueInto + GlueInto + GlueInto + + GlueInto { type VmM6Mode: crate::vm_m6::HistoryMode; type Vm1_3_2Mode: crate::vm_1_3_2::HistoryMode; type VmVirtualBlocksMode: crate::vm_virtual_blocks::HistoryMode; type VmVirtualBlocksRefundsEnhancement: crate::vm_refunds_enhancement::HistoryMode; type VmBoojumIntegration: crate::vm_boojum_integration::HistoryMode; - type Vm1_4_1: crate::vm_latest::HistoryMode; + type Vm1_4_1: crate::vm_1_4_1::HistoryMode; + type Vm1_4_2: crate::vm_latest::HistoryMode; } impl GlueFrom for crate::vm_m6::HistoryEnabled { @@ -47,6 +49,12 @@ impl GlueFrom for crate::vm_boojum_integration } } +impl GlueFrom for crate::vm_1_4_1::HistoryEnabled { + fn glue_from(_: crate::vm_latest::HistoryEnabled) -> Self { + Self + } +} + impl GlueFrom for crate::vm_m6::HistoryDisabled { fn glue_from(_: crate::vm_latest::HistoryDisabled) -> Self { Self @@ -79,13 +87,20 @@ impl GlueFrom for crate::vm_boojum_integratio } } +impl GlueFrom for crate::vm_1_4_1::HistoryDisabled { + fn glue_from(_: crate::vm_latest::HistoryDisabled) -> Self { + Self + } +} + impl HistoryMode for crate::vm_latest::HistoryEnabled { type VmM6Mode = crate::vm_m6::HistoryEnabled; type Vm1_3_2Mode = crate::vm_1_3_2::HistoryEnabled; type VmVirtualBlocksMode = crate::vm_virtual_blocks::HistoryEnabled; type VmVirtualBlocksRefundsEnhancement = crate::vm_refunds_enhancement::HistoryEnabled; type VmBoojumIntegration = crate::vm_boojum_integration::HistoryEnabled; - type Vm1_4_1 = crate::vm_latest::HistoryEnabled; + type Vm1_4_1 = crate::vm_1_4_1::HistoryEnabled; + type Vm1_4_2 = crate::vm_latest::HistoryEnabled; } impl HistoryMode for crate::vm_latest::HistoryDisabled { @@ -94,5 +109,6 @@ impl HistoryMode for crate::vm_latest::HistoryDisabled { type VmVirtualBlocksMode = crate::vm_virtual_blocks::HistoryDisabled; type VmVirtualBlocksRefundsEnhancement = crate::vm_refunds_enhancement::HistoryDisabled; type VmBoojumIntegration = crate::vm_boojum_integration::HistoryDisabled; - type Vm1_4_1 = crate::vm_latest::HistoryDisabled; + type Vm1_4_1 = crate::vm_1_4_1::HistoryDisabled; + type Vm1_4_2 = crate::vm_latest::HistoryDisabled; } diff --git a/core/lib/multivm/src/glue/tracers/mod.rs b/core/lib/multivm/src/glue/tracers/mod.rs index 3ca26892113c..46a7acf0665f 100644 --- a/core/lib/multivm/src/glue/tracers/mod.rs +++ b/core/lib/multivm/src/glue/tracers/mod.rs @@ -41,6 +41,7 @@ pub trait MultiVMTracer: + IntoVmVirtualBlocksTracer + IntoVmRefundsEnhancementTracer + IntoVmBoojumIntegrationTracer + + IntoVm1_4_1IntegrationTracer + IntoOldVmTracer { fn into_tracer_pointer(self) -> MultiVmTracerPointer @@ -52,7 +53,7 @@ pub trait MultiVMTracer: } pub trait IntoLatestTracer { - fn latest(&self) -> crate::vm_latest::TracerPointer; + fn latest(&self) -> crate::vm_latest::TracerPointer; } pub trait IntoVmVirtualBlocksTracer { @@ -73,6 +74,10 @@ pub trait IntoVmBoojumIntegrationTracer { ) -> Box>; } +pub trait IntoVm1_4_1IntegrationTracer { + fn vm_1_4_1(&self) -> Box>; +} + /// Into tracers for old VM versions. /// Even though number of tracers is limited, we still need to have this trait to be able to convert /// tracers to old VM tracers. @@ -89,9 +94,9 @@ impl IntoLatestTracer for T where S: WriteStorage, H: HistoryMode, - T: crate::vm_latest::VmTracer + Clone + 'static, + T: crate::vm_latest::VmTracer + Clone + 'static, { - fn latest(&self) -> crate::vm_latest::TracerPointer { + fn latest(&self) -> crate::vm_latest::TracerPointer { Box::new(self.clone()) } } @@ -138,6 +143,17 @@ where } } +impl IntoVm1_4_1IntegrationTracer for T +where + S: WriteStorage, + H: HistoryMode, + T: crate::vm_1_4_1::VmTracer + Clone + 'static, +{ + fn vm_1_4_1(&self) -> Box> { + Box::new(self.clone()) + } +} + impl MultiVMTracer for T where S: WriteStorage, @@ -146,6 +162,7 @@ where + IntoVmVirtualBlocksTracer + IntoVmRefundsEnhancementTracer + IntoVmBoojumIntegrationTracer + + IntoVm1_4_1IntegrationTracer + IntoOldVmTracer, { } diff --git a/core/lib/multivm/src/glue/types/vm/storage_query.rs b/core/lib/multivm/src/glue/types/vm/storage_query.rs index 21a10947e09b..19c543954e35 100644 --- a/core/lib/multivm/src/glue/types/vm/storage_query.rs +++ b/core/lib/multivm/src/glue/types/vm/storage_query.rs @@ -56,6 +56,15 @@ impl GlueFrom for St } } +impl GlueFrom for StorageLogQuery { + fn glue_from(value: crate::vm_1_4_1::utils::logs::StorageLogQuery) -> Self { + Self { + log_query: value.log_query.glue_into(), + log_type: value.log_type, + } + } +} + impl GlueFrom for StorageLogQuery { fn glue_from(value: crate::vm_latest::utils::logs::StorageLogQuery) -> Self { Self { diff --git a/core/lib/multivm/src/lib.rs b/core/lib/multivm/src/lib.rs index aa55026d88fe..b8278257f526 100644 --- a/core/lib/multivm/src/lib.rs +++ b/core/lib/multivm/src/lib.rs @@ -7,7 +7,7 @@ pub use zkevm_test_harness_1_4_1 as zkevm_test_harness_latest; pub use zksync_types::vm_version::VmVersion; pub use self::versions::{ - vm_1_3_2, vm_boojum_integration, vm_latest, vm_m5, vm_m6, vm_refunds_enhancement, + vm_1_3_2, vm_1_4_1, vm_boojum_integration, vm_latest, vm_m5, vm_m6, vm_refunds_enhancement, vm_virtual_blocks, }; pub use crate::{ diff --git a/core/lib/multivm/src/tracers/call_tracer/mod.rs b/core/lib/multivm/src/tracers/call_tracer/mod.rs index b3a98902f4b9..989db54d968f 100644 --- a/core/lib/multivm/src/tracers/call_tracer/mod.rs +++ b/core/lib/multivm/src/tracers/call_tracer/mod.rs @@ -6,6 +6,7 @@ use zksync_types::vm_trace::Call; use crate::{glue::tracers::IntoOldVmTracer, tracers::call_tracer::metrics::CALL_METRICS}; mod metrics; +pub mod vm_1_4_1; pub mod vm_boojum_integration; pub mod vm_latest; pub mod vm_refunds_enhancement; diff --git a/core/lib/multivm/src/tracers/call_tracer/vm_1_4_1/mod.rs b/core/lib/multivm/src/tracers/call_tracer/vm_1_4_1/mod.rs new file mode 100644 index 000000000000..54809168fca8 --- /dev/null +++ b/core/lib/multivm/src/tracers/call_tracer/vm_1_4_1/mod.rs @@ -0,0 +1,209 @@ +use zk_evm_1_4_1::{ + tracing::{AfterExecutionData, VmLocalStateData}, + zkevm_opcode_defs::{ + FarCallABI, FatPointer, Opcode, RetOpcode, CALL_IMPLICIT_CALLDATA_FAT_PTR_REGISTER, + RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER, + }, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_system_constants::CONTRACT_DEPLOYER_ADDRESS; +use zksync_types::{ + vm_trace::{Call, CallType}, + zk_evm_types::FarCallOpcode, + U256, +}; + +use crate::{ + glue::GlueInto, + interface::{ + tracer::VmExecutionStopReason, traits::tracers::dyn_tracers::vm_1_4_1::DynTracer, + VmRevertReason, + }, + tracers::call_tracer::CallTracer, + vm_1_4_1::{BootloaderState, HistoryMode, SimpleMemory, VmTracer, ZkSyncVmState}, +}; + +impl DynTracer> for CallTracer { + fn after_execution( + &mut self, + state: VmLocalStateData<'_>, + data: AfterExecutionData, + memory: &SimpleMemory, + _storage: StoragePtr, + ) { + match data.opcode.variant.opcode { + Opcode::NearCall(_) => { + self.increase_near_call_count(); + } + Opcode::FarCall(far_call) => { + // We use parent gas for properly calculating gas used in the trace. + let current_ergs = state.vm_local_state.callstack.current.ergs_remaining; + let parent_gas = state + .vm_local_state + .callstack + .inner + .last() + .map(|call| call.ergs_remaining + current_ergs) + .unwrap_or(current_ergs); + + let mut current_call = Call { + r#type: CallType::Call(far_call.glue_into()), + gas: 0, + parent_gas, + ..Default::default() + }; + + self.handle_far_call_op_code_vm_1_4_1(state, memory, &mut current_call); + self.push_call_and_update_stats(current_call, 0); + } + Opcode::Ret(ret_code) => { + self.handle_ret_op_code_vm_1_4_1(state, memory, ret_code); + } + _ => {} + }; + } +} + +impl VmTracer for CallTracer { + fn after_vm_execution( + &mut self, + _state: &mut ZkSyncVmState, + _bootloader_state: &BootloaderState, + _stop_reason: VmExecutionStopReason, + ) { + self.store_result() + } +} + +impl CallTracer { + fn handle_far_call_op_code_vm_1_4_1( + &mut self, + state: VmLocalStateData<'_>, + memory: &SimpleMemory, + current_call: &mut Call, + ) { + let current = state.vm_local_state.callstack.current; + // All calls from the actual users are mimic calls, + // so we need to check that the previous call was to the deployer. + // Actually it's a call of the constructor. + // And at this stage caller is user and callee is deployed contract. + let call_type = if let CallType::Call(far_call) = current_call.r#type { + if matches!(far_call, FarCallOpcode::Mimic) { + let previous_caller = state + .vm_local_state + .callstack + .inner + .last() + .map(|call| call.this_address) + // Actually it's safe to just unwrap here, because we have at least one call in the stack + // But i want to be sure that we will not have any problems in the future + .unwrap_or(current.this_address); + if previous_caller == CONTRACT_DEPLOYER_ADDRESS { + CallType::Create + } else { + CallType::Call(far_call) + } + } else { + CallType::Call(far_call) + } + } else { + unreachable!() + }; + let calldata = if current.code_page.0 == 0 || current.ergs_remaining == 0 { + vec![] + } else { + let packed_abi = + state.vm_local_state.registers[CALL_IMPLICIT_CALLDATA_FAT_PTR_REGISTER as usize]; + assert!(packed_abi.is_pointer); + let far_call_abi = FarCallABI::from_u256(packed_abi.value); + memory.read_unaligned_bytes( + far_call_abi.memory_quasi_fat_pointer.memory_page as usize, + far_call_abi.memory_quasi_fat_pointer.start as usize, + far_call_abi.memory_quasi_fat_pointer.length as usize, + ) + }; + + current_call.input = calldata; + current_call.r#type = call_type; + current_call.from = current.msg_sender; + current_call.to = current.this_address; + current_call.value = U256::from(current.context_u128_value); + current_call.gas = current.ergs_remaining; + } + + fn save_output_vm_1_4_1( + &mut self, + state: VmLocalStateData<'_>, + memory: &SimpleMemory, + ret_opcode: RetOpcode, + current_call: &mut Call, + ) { + let fat_data_pointer = + state.vm_local_state.registers[RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER as usize]; + + // if `fat_data_pointer` is not a pointer then there is no output + let output = if fat_data_pointer.is_pointer { + let fat_data_pointer = FatPointer::from_u256(fat_data_pointer.value); + if !fat_data_pointer.is_trivial() { + Some(memory.read_unaligned_bytes( + fat_data_pointer.memory_page as usize, + fat_data_pointer.start as usize, + fat_data_pointer.length as usize, + )) + } else { + None + } + } else { + None + }; + + match ret_opcode { + RetOpcode::Ok => { + current_call.output = output.unwrap_or_default(); + } + RetOpcode::Revert => { + if let Some(output) = output { + current_call.revert_reason = + Some(VmRevertReason::from(output.as_slice()).to_string()); + } else { + current_call.revert_reason = Some("Unknown revert reason".to_string()); + } + } + RetOpcode::Panic => { + current_call.error = Some("Panic".to_string()); + } + } + } + + fn handle_ret_op_code_vm_1_4_1( + &mut self, + state: VmLocalStateData<'_>, + memory: &SimpleMemory, + ret_opcode: RetOpcode, + ) { + let Some(mut current_call) = self.stack.pop() else { + return; + }; + + if current_call.near_calls_after > 0 { + current_call.near_calls_after -= 1; + self.push_call_and_update_stats(current_call.farcall, current_call.near_calls_after); + return; + } + + current_call.farcall.gas_used = current_call + .farcall + .parent_gas + .saturating_sub(state.vm_local_state.callstack.current.ergs_remaining); + + self.save_output_vm_1_4_1(state, memory, ret_opcode, &mut current_call.farcall); + + // If there is a parent call, push the current call to it + // Otherwise, push the current call to the stack, because it's the top level call + if let Some(parent_call) = self.stack.last_mut() { + parent_call.farcall.calls.push(current_call.farcall); + } else { + self.push_call_and_update_stats(current_call.farcall, current_call.near_calls_after); + } + } +} diff --git a/core/lib/multivm/src/tracers/multivm_dispatcher.rs b/core/lib/multivm/src/tracers/multivm_dispatcher.rs index 0e8585884fa5..b616c571f77c 100644 --- a/core/lib/multivm/src/tracers/multivm_dispatcher.rs +++ b/core/lib/multivm/src/tracers/multivm_dispatcher.rs @@ -30,7 +30,7 @@ impl Default for TracerDispatcher { } impl From> - for crate::vm_latest::TracerDispatcher + for crate::vm_latest::TracerDispatcher { fn from(value: TracerDispatcher) -> Self { Self::new(value.tracers.into_iter().map(|x| x.latest()).collect()) @@ -51,6 +51,14 @@ impl From> } } +impl From> + for crate::vm_1_4_1::TracerDispatcher +{ + fn from(value: TracerDispatcher) -> Self { + Self::new(value.tracers.into_iter().map(|x| x.vm_1_4_1()).collect()) + } +} + impl From> for crate::vm_refunds_enhancement::TracerDispatcher { diff --git a/core/lib/multivm/src/tracers/storage_invocation/mod.rs b/core/lib/multivm/src/tracers/storage_invocation/mod.rs index db4e936e0112..210a175507b9 100644 --- a/core/lib/multivm/src/tracers/storage_invocation/mod.rs +++ b/core/lib/multivm/src/tracers/storage_invocation/mod.rs @@ -1,5 +1,6 @@ use crate::{glue::tracers::IntoOldVmTracer, tracers::old_tracers::OldTracers}; +pub mod vm_1_4_1; pub mod vm_boojum_integration; pub mod vm_latest; pub mod vm_refunds_enhancement; diff --git a/core/lib/multivm/src/tracers/storage_invocation/vm_1_4_1/mod.rs b/core/lib/multivm/src/tracers/storage_invocation/vm_1_4_1/mod.rs new file mode 100644 index 000000000000..be3a30adb1d4 --- /dev/null +++ b/core/lib/multivm/src/tracers/storage_invocation/vm_1_4_1/mod.rs @@ -0,0 +1,35 @@ +use zksync_state::WriteStorage; + +use crate::{ + interface::{ + tracer::{TracerExecutionStatus, TracerExecutionStopReason}, + traits::tracers::dyn_tracers::vm_1_4_1::DynTracer, + Halt, + }, + tracers::storage_invocation::StorageInvocations, + vm_1_4_1::{BootloaderState, HistoryMode, SimpleMemory, VmTracer, ZkSyncVmState}, +}; + +impl DynTracer> for StorageInvocations {} + +impl VmTracer for StorageInvocations { + fn finish_cycle( + &mut self, + state: &mut ZkSyncVmState, + _bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + let current = state + .storage + .storage + .get_ptr() + .borrow() + .missed_storage_invocations(); + + if current >= self.limit { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Abort( + Halt::TracerCustom("Storage invocations limit reached".to_string()), + )); + } + TracerExecutionStatus::Continue + } +} diff --git a/core/lib/multivm/src/tracers/validator/mod.rs b/core/lib/multivm/src/tracers/validator/mod.rs index c56424f3013e..caf9dee30c9d 100644 --- a/core/lib/multivm/src/tracers/validator/mod.rs +++ b/core/lib/multivm/src/tracers/validator/mod.rs @@ -19,6 +19,7 @@ use crate::{ }; mod types; +mod vm_1_4_1; mod vm_boojum_integration; mod vm_latest; mod vm_refunds_enhancement; diff --git a/core/lib/multivm/src/tracers/validator/vm_1_4_1/mod.rs b/core/lib/multivm/src/tracers/validator/vm_1_4_1/mod.rs new file mode 100644 index 000000000000..81d885fa788e --- /dev/null +++ b/core/lib/multivm/src/tracers/validator/vm_1_4_1/mod.rs @@ -0,0 +1,201 @@ +use zk_evm_1_4_1::{ + tracing::{BeforeExecutionData, VmLocalStateData}, + zkevm_opcode_defs::{ContextOpcode, FarCallABI, LogOpcode, Opcode}, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_system_constants::KECCAK256_PRECOMPILE_ADDRESS; +use zksync_types::{ + get_code_key, vm_trace::ViolatedValidationRule, AccountTreeId, StorageKey, H256, +}; +use zksync_utils::{h256_to_account_address, u256_to_account_address, u256_to_h256}; + +use crate::{ + interface::{ + traits::tracers::dyn_tracers::vm_1_4_1::DynTracer, + types::tracer::{TracerExecutionStatus, TracerExecutionStopReason}, + Halt, + }, + tracers::validator::{ + types::{NewTrustedValidationItems, ValidationTracerMode}, + ValidationRoundResult, ValidationTracer, + }, + vm_1_4_1::{ + tracers::utils::{ + computational_gas_price, get_calldata_page_via_abi, print_debug_if_needed, VmHook, + }, + BootloaderState, SimpleMemory, VmTracer, ZkSyncVmState, + }, + HistoryMode, +}; + +impl ValidationTracer { + fn check_user_restrictions_vm_1_4_1( + &mut self, + state: VmLocalStateData<'_>, + data: BeforeExecutionData, + memory: &SimpleMemory, + storage: StoragePtr, + ) -> ValidationRoundResult { + if self.computational_gas_used > self.computational_gas_limit { + return Err(ViolatedValidationRule::TookTooManyComputationalGas( + self.computational_gas_limit, + )); + } + + let opcode_variant = data.opcode.variant; + match opcode_variant.opcode { + Opcode::FarCall(_) => { + let packed_abi = data.src0_value.value; + let call_destination_value = data.src1_value.value; + + let called_address = u256_to_account_address(&call_destination_value); + let far_call_abi = FarCallABI::from_u256(packed_abi); + + if called_address == KECCAK256_PRECOMPILE_ADDRESS + && far_call_abi.memory_quasi_fat_pointer.length == 64 + { + let calldata_page = get_calldata_page_via_abi( + &far_call_abi, + state.vm_local_state.callstack.current.base_memory_page, + ); + let calldata = memory.read_unaligned_bytes( + calldata_page as usize, + far_call_abi.memory_quasi_fat_pointer.start as usize, + 64, + ); + + let slot_to_add = + self.slot_to_add_from_keccak_call(&calldata, self.user_address); + + if let Some(slot) = slot_to_add { + return Ok(NewTrustedValidationItems { + new_allowed_slots: vec![slot], + ..Default::default() + }); + } + } else if called_address != self.user_address { + let code_key = get_code_key(&called_address); + let code = storage.borrow_mut().read_value(&code_key); + + if code == H256::zero() { + // The users are not allowed to call contracts with no code + return Err(ViolatedValidationRule::CalledContractWithNoCode( + called_address, + )); + } + } + } + Opcode::Context(context) => { + match context { + ContextOpcode::Meta => { + return Err(ViolatedValidationRule::TouchedUnallowedContext); + } + ContextOpcode::ErgsLeft => { + // TODO (SMA-1168): implement the correct restrictions for the gas left opcode. + } + _ => {} + } + } + Opcode::Log(LogOpcode::StorageRead) => { + let key = data.src0_value.value; + let this_address = state.vm_local_state.callstack.current.this_address; + let msg_sender = state.vm_local_state.callstack.current.msg_sender; + + if !self.is_allowed_storage_read(storage.clone(), this_address, key, msg_sender) { + return Err(ViolatedValidationRule::TouchedUnallowedStorageSlots( + this_address, + key, + )); + } + + if self.trusted_address_slots.contains(&(this_address, key)) { + let storage_key = + StorageKey::new(AccountTreeId::new(this_address), u256_to_h256(key)); + + let value = storage.borrow_mut().read_value(&storage_key); + + return Ok(NewTrustedValidationItems { + new_trusted_addresses: vec![h256_to_account_address(&value)], + ..Default::default() + }); + } + } + _ => {} + } + + Ok(Default::default()) + } +} + +impl DynTracer> + for ValidationTracer +{ + fn before_execution( + &mut self, + state: VmLocalStateData<'_>, + data: BeforeExecutionData, + memory: &SimpleMemory, + storage: StoragePtr, + ) { + // For now, we support only validations for users. + if let ValidationTracerMode::UserTxValidation = self.validation_mode { + self.computational_gas_used = self + .computational_gas_used + .saturating_add(computational_gas_price(state, &data)); + + let validation_round_result = + self.check_user_restrictions_vm_1_4_1(state, data, memory, storage); + self.process_validation_round_result(validation_round_result); + } + + let hook = VmHook::from_opcode_memory(&state, &data); + print_debug_if_needed(&hook, &state, memory); + + let current_mode = self.validation_mode; + match (current_mode, hook) { + (ValidationTracerMode::NoValidation, VmHook::AccountValidationEntered) => { + // Account validation can be entered when there is no prior validation (i.e. "nested" validations are not allowed) + self.validation_mode = ValidationTracerMode::UserTxValidation; + } + (ValidationTracerMode::NoValidation, VmHook::PaymasterValidationEntered) => { + // Paymaster validation can be entered when there is no prior validation (i.e. "nested" validations are not allowed) + self.validation_mode = ValidationTracerMode::PaymasterTxValidation; + } + (_, VmHook::AccountValidationEntered | VmHook::PaymasterValidationEntered) => { + panic!( + "Unallowed transition inside the validation tracer. Mode: {:#?}, hook: {:#?}", + self.validation_mode, hook + ); + } + (_, VmHook::NoValidationEntered) => { + // Validation can be always turned off + self.validation_mode = ValidationTracerMode::NoValidation; + } + (_, VmHook::ValidationStepEndeded) => { + // The validation step has ended. + self.should_stop_execution = true; + } + (_, _) => { + // The hook is not relevant to the validation tracer. Ignore. + } + } + } +} + +impl VmTracer for ValidationTracer { + fn finish_cycle( + &mut self, + _state: &mut ZkSyncVmState, + _bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + if self.should_stop_execution { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Finish); + } + if let Some(result) = self.result.get() { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Abort( + Halt::TracerCustom(format!("Validation error: {:#?}", result)), + )); + } + TracerExecutionStatus::Continue + } +} diff --git a/core/lib/multivm/src/tracers/validator/vm_latest/mod.rs b/core/lib/multivm/src/tracers/validator/vm_latest/mod.rs index 095f1a20b38b..a2096ee68961 100644 --- a/core/lib/multivm/src/tracers/validator/vm_latest/mod.rs +++ b/core/lib/multivm/src/tracers/validator/vm_latest/mod.rs @@ -33,7 +33,7 @@ impl ValidationTracer { &mut self, state: VmLocalStateData<'_>, data: BeforeExecutionData, - memory: &SimpleMemory, + memory: &SimpleMemory, storage: StoragePtr, ) -> ValidationRoundResult { if self.computational_gas_used > self.computational_gas_limit { @@ -127,14 +127,14 @@ impl ValidationTracer { } } -impl DynTracer> +impl DynTracer> for ValidationTracer { fn before_execution( &mut self, state: VmLocalStateData<'_>, data: BeforeExecutionData, - memory: &SimpleMemory, + memory: &SimpleMemory, storage: StoragePtr, ) { // For now, we support only validations for users. @@ -182,10 +182,10 @@ impl DynTracer> } } -impl VmTracer for ValidationTracer { +impl VmTracer for ValidationTracer { fn finish_cycle( &mut self, - _state: &mut ZkSyncVmState, + _state: &mut ZkSyncVmState, _bootloader_state: &mut BootloaderState, ) -> TracerExecutionStatus { if self.should_stop_execution { diff --git a/core/lib/multivm/src/utils.rs b/core/lib/multivm/src/utils.rs index 1488ee3df19d..9f5ae5540c39 100644 --- a/core/lib/multivm/src/utils.rs +++ b/core/lib/multivm/src/utils.rs @@ -1,4 +1,7 @@ -use zksync_types::{fee_model::BatchFeeInput, VmVersion, U256}; +use zksync_types::{ + fee_model::{BatchFeeInput, L1PeggedBatchFeeModelInput, PubdataIndependentBatchFeeModelInput}, + VmVersion, U256, +}; use crate::vm_latest::L1BatchEnv; @@ -38,7 +41,10 @@ pub fn derive_base_fee_and_gas_per_pubdata( batch_fee_input.into_l1_pegged(), ) } - VmVersion::Vm1_4_1 => crate::vm_latest::utils::fee::derive_base_fee_and_gas_per_pubdata( + VmVersion::Vm1_4_1 => crate::vm_1_4_1::utils::fee::derive_base_fee_and_gas_per_pubdata( + batch_fee_input.into_pubdata_independent(), + ), + VmVersion::Vm1_4_2 => crate::vm_latest::utils::fee::derive_base_fee_and_gas_per_pubdata( batch_fee_input.into_pubdata_independent(), ), } @@ -62,7 +68,8 @@ pub fn get_batch_base_fee(l1_batch_env: &L1BatchEnv, vm_version: VmVersion) -> u VmVersion::VmBoojumIntegration => { crate::vm_boojum_integration::utils::fee::get_batch_base_fee(l1_batch_env) } - VmVersion::Vm1_4_1 => crate::vm_latest::utils::fee::get_batch_base_fee(l1_batch_env), + VmVersion::Vm1_4_1 => crate::vm_1_4_1::utils::fee::get_batch_base_fee(l1_batch_env), + VmVersion::Vm1_4_2 => crate::vm_latest::utils::fee::get_batch_base_fee(l1_batch_env), } } @@ -75,14 +82,37 @@ pub fn adjust_pubdata_price_for_tx( if U256::from(derive_base_fee_and_gas_per_pubdata(batch_fee_input, vm_version).1) <= tx_gas_per_pubdata_limit { + // gas per pubdata is already smaller than or equal to `tx_gas_per_pubdata_limit`. return batch_fee_input; } - // The latest VM supports adjusting the pubdata price for all the types of the fee models. - crate::vm_latest::utils::fee::adjust_pubdata_price_for_tx( - batch_fee_input, - tx_gas_per_pubdata_limit, - ) + match batch_fee_input { + BatchFeeInput::L1Pegged(fee_input) => { + // `gasPerPubdata = ceil(17 * l1gasprice / fair_l2_gas_price)` + // `gasPerPubdata <= 17 * l1gasprice / fair_l2_gas_price + 1` + // `fair_l2_gas_price(gasPerPubdata - 1) / 17 <= l1gasprice` + let new_l1_gas_price = U256::from(fee_input.fair_l2_gas_price) + * (tx_gas_per_pubdata_limit - U256::from(1u32)) + / U256::from(17); + + BatchFeeInput::L1Pegged(L1PeggedBatchFeeModelInput { + l1_gas_price: new_l1_gas_price.as_u64(), + ..fee_input + }) + } + BatchFeeInput::PubdataIndependent(fee_input) => { + // `gasPerPubdata = ceil(fair_pubdata_price / fair_l2_gas_price)` + // `gasPerPubdata <= fair_pubdata_price / fair_l2_gas_price + 1` + // `fair_l2_gas_price(gasPerPubdata - 1) <= fair_pubdata_price` + let new_fair_pubdata_price = U256::from(fee_input.fair_l2_gas_price) + * (tx_gas_per_pubdata_limit - U256::from(1u32)); + + BatchFeeInput::PubdataIndependent(PubdataIndependentBatchFeeModelInput { + fair_pubdata_price: new_fair_pubdata_price.as_u64(), + ..fee_input + }) + } + } } pub fn derive_overhead( @@ -140,7 +170,8 @@ pub fn derive_overhead( ), ) } - VmVersion::Vm1_4_1 => crate::vm_latest::utils::overhead::derive_overhead(encoded_len), + VmVersion::Vm1_4_1 => crate::vm_1_4_1::utils::overhead::derive_overhead(encoded_len), + VmVersion::Vm1_4_2 => crate::vm_latest::utils::overhead::derive_overhead(encoded_len), } } @@ -162,7 +193,8 @@ pub fn get_bootloader_encoding_space(version: VmVersion) -> u32 { VmVersion::VmBoojumIntegration => { crate::vm_boojum_integration::constants::BOOTLOADER_TX_ENCODING_SPACE } - VmVersion::Vm1_4_1 => crate::vm_latest::constants::BOOTLOADER_TX_ENCODING_SPACE, + VmVersion::Vm1_4_1 => crate::vm_1_4_1::constants::BOOTLOADER_TX_ENCODING_SPACE, + VmVersion::Vm1_4_2 => crate::vm_latest::constants::BOOTLOADER_TX_ENCODING_SPACE, } } @@ -180,7 +212,8 @@ pub fn get_bootloader_max_txs_in_batch(version: VmVersion) -> usize { crate::vm_refunds_enhancement::constants::MAX_TXS_IN_BLOCK } VmVersion::VmBoojumIntegration => crate::vm_boojum_integration::constants::MAX_TXS_IN_BLOCK, - VmVersion::Vm1_4_1 => crate::vm_latest::constants::MAX_TXS_IN_BATCH, + VmVersion::Vm1_4_1 => crate::vm_1_4_1::constants::MAX_TXS_IN_BATCH, + VmVersion::Vm1_4_2 => crate::vm_latest::constants::MAX_TXS_IN_BATCH, } } @@ -199,7 +232,8 @@ pub fn gas_bootloader_batch_tip_overhead(version: VmVersion) -> u32 { VmVersion::VmBoojumIntegration => { crate::vm_boojum_integration::constants::BOOTLOADER_BATCH_TIP_OVERHEAD } - VmVersion::Vm1_4_1 => crate::vm_latest::constants::BOOTLOADER_BATCH_TIP_OVERHEAD, + VmVersion::Vm1_4_1 => crate::vm_1_4_1::constants::BOOTLOADER_BATCH_TIP_OVERHEAD, + VmVersion::Vm1_4_2 => crate::vm_latest::constants::BOOTLOADER_BATCH_TIP_OVERHEAD, } } @@ -220,6 +254,7 @@ pub fn get_max_gas_per_pubdata_byte(version: VmVersion) -> u64 { crate::vm_boojum_integration::constants::MAX_GAS_PER_PUBDATA_BYTE } VmVersion::Vm1_4_1 => crate::vm_latest::constants::MAX_GAS_PER_PUBDATA_BYTE, + VmVersion::Vm1_4_2 => crate::vm_1_4_1::constants::MAX_GAS_PER_PUBDATA_BYTE, } } @@ -241,7 +276,8 @@ pub fn get_used_bootloader_memory_bytes(version: VmVersion) -> usize { VmVersion::VmBoojumIntegration => { crate::vm_boojum_integration::constants::USED_BOOTLOADER_MEMORY_BYTES } - VmVersion::Vm1_4_1 => crate::vm_latest::constants::USED_BOOTLOADER_MEMORY_BYTES, + VmVersion::Vm1_4_1 => crate::vm_1_4_1::constants::USED_BOOTLOADER_MEMORY_BYTES, + VmVersion::Vm1_4_2 => crate::vm_latest::constants::USED_BOOTLOADER_MEMORY_BYTES, } } @@ -263,6 +299,7 @@ pub fn get_used_bootloader_memory_words(version: VmVersion) -> usize { VmVersion::VmBoojumIntegration => { crate::vm_boojum_integration::constants::USED_BOOTLOADER_MEMORY_WORDS } - VmVersion::Vm1_4_1 => crate::vm_latest::constants::USED_BOOTLOADER_MEMORY_WORDS, + VmVersion::Vm1_4_1 => crate::vm_1_4_1::constants::USED_BOOTLOADER_MEMORY_WORDS, + VmVersion::Vm1_4_2 => crate::vm_latest::constants::USED_BOOTLOADER_MEMORY_WORDS, } } diff --git a/core/lib/multivm/src/versions/mod.rs b/core/lib/multivm/src/versions/mod.rs index 0fc9111aa9a2..a13946c3852c 100644 --- a/core/lib/multivm/src/versions/mod.rs +++ b/core/lib/multivm/src/versions/mod.rs @@ -1,4 +1,5 @@ pub mod vm_1_3_2; +pub mod vm_1_4_1; pub mod vm_boojum_integration; pub mod vm_latest; pub mod vm_m5; diff --git a/core/lib/multivm/src/versions/vm_1_4_1/implementation/snapshots.rs b/core/lib/multivm/src/versions/vm_1_4_1/implementation/snapshots.rs index 2682b6183c52..08e4e1c9e49e 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/implementation/snapshots.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/implementation/snapshots.rs @@ -4,11 +4,7 @@ use vise::{Buckets, EncodeLabelSet, EncodeLabelValue, Family, Histogram, Metrics use zk_evm_1_4_1::aux_structures::Timestamp; use zksync_state::WriteStorage; -use crate::vm_1_4_1::{ - old_vm::{history_recorder::HistoryEnabled, oracles::OracleWithHistory}, - types::internals::VmSnapshot, - vm::Vm, -}; +use crate::vm_1_4_1::{old_vm::oracles::OracleWithHistory, types::internals::VmSnapshot, vm::Vm}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelSet, EncodeLabelValue)] #[metrics(label = "stage", rename_all = "snake_case")] @@ -22,7 +18,7 @@ enum RollbackStage { } #[derive(Debug, Metrics)] -#[metrics(prefix = "server_vm")] +#[metrics(prefix = "server_vm_1_4_1")] struct VmMetrics { #[metrics(buckets = Buckets::LATENCIES)] rollback_time: Family>, @@ -32,7 +28,7 @@ struct VmMetrics { static METRICS: vise::Global = vise::Global::new(); /// Implementation of VM related to rollbacks inside virtual machine -impl Vm { +impl Vm { pub(crate) fn make_snapshot_inner(&mut self) { self.snapshots.push(VmSnapshot { // Vm local state contains O(1) various parameters (registers/etc). diff --git a/core/lib/multivm/src/versions/vm_1_4_1/mod.rs b/core/lib/multivm/src/versions/vm_1_4_1/mod.rs index c3df28f6c31c..83693e4b24e9 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/mod.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/mod.rs @@ -28,8 +28,6 @@ pub mod constants; mod implementation; mod old_vm; mod oracles; -#[cfg(test)] -mod tests; pub(crate) mod tracers; mod types; pub mod utils; diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tracers/pubdata_tracer.rs b/core/lib/multivm/src/versions/vm_1_4_1/tracers/pubdata_tracer.rs index c69daa0927b5..831466be318c 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/tracers/pubdata_tracer.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/tracers/pubdata_tracer.rs @@ -57,23 +57,6 @@ impl PubdataTracer { } } - // Creates the pubdata tracer with constant state diffs. - // To be used in tests only. - #[cfg(test)] - pub(crate) fn new_with_forced_state_diffs( - l1_batch_env: L1BatchEnv, - execution_mode: VmExecutionMode, - forced_state_diffs: Vec, - ) -> Self { - Self { - l1_batch_env, - pubdata_info_requested: false, - execution_mode, - enforced_state_diffs: Some(forced_state_diffs), - _phantom_data: Default::default(), - } - } - // Packs part of L1 Messenger total pubdata that corresponds to // `L2toL1Logs` sent in the block fn get_total_user_logs( diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tracers/refunds.rs b/core/lib/multivm/src/versions/vm_1_4_1/tracers/refunds.rs index 9fba21c42078..6f942a807e78 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/tracers/refunds.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/tracers/refunds.rs @@ -212,7 +212,7 @@ impl VmTracer for RefundsTracer { ]); #[derive(Debug, Metrics)] - #[metrics(prefix = "vm")] + #[metrics(prefix = "vm_1_4_1")] struct RefundMetrics { #[metrics(buckets = PERCENT_BUCKETS)] refund: Family>, diff --git a/core/lib/multivm/src/versions/vm_1_4_1/utils/fee.rs b/core/lib/multivm/src/versions/vm_1_4_1/utils/fee.rs index beb85468241b..6498a86d3536 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/utils/fee.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/utils/fee.rs @@ -1,8 +1,5 @@ //! Utility functions for vm -use zksync_types::{ - fee_model::{BatchFeeInput, PubdataIndependentBatchFeeModelInput}, - U256, -}; +use zksync_types::fee_model::PubdataIndependentBatchFeeModelInput; use zksync_utils::ceil_div; use crate::vm_1_4_1::{constants::MAX_GAS_PER_PUBDATA_BYTE, L1BatchEnv}; @@ -37,34 +34,3 @@ pub(crate) fn get_batch_base_fee(l1_batch_env: &L1BatchEnv) -> u64 { derive_base_fee_and_gas_per_pubdata(l1_batch_env.fee_input.into_pubdata_independent()); base_fee } - -/// Changes the fee model output so that the expected gas per pubdata is smaller than or the `tx_gas_per_pubdata_limit`. -/// This function expects that the currently expected gas per pubdata is greater than the `tx_gas_per_pubdata_limit`. -pub(crate) fn adjust_pubdata_price_for_tx( - mut batch_fee_input: BatchFeeInput, - tx_gas_per_pubdata_limit: U256, -) -> BatchFeeInput { - match &mut batch_fee_input { - BatchFeeInput::L1Pegged(fee_input) => { - // `gasPerPubdata = ceil(17 * l1gasprice / fair_l2_gas_price)` - // `gasPerPubdata <= 17 * l1gasprice / fair_l2_gas_price + 1` - // `fair_l2_gas_price(gasPerPubdata - 1) / 17 <= l1gasprice` - let new_l1_gas_price = U256::from(fee_input.fair_l2_gas_price) - * (tx_gas_per_pubdata_limit - U256::from(1u32)) - / U256::from(17); - - fee_input.l1_gas_price = new_l1_gas_price.as_u64(); - } - BatchFeeInput::PubdataIndependent(fee_input) => { - // `gasPerPubdata = ceil(fair_pubdata_price / fair_l2_gas_price)` - // `gasPerPubdata <= fair_pubdata_price / fair_l2_gas_price + 1` - // `fair_l2_gas_price(gasPerPubdata - 1) <= fair_pubdata_price` - let new_fair_pubdata_price = U256::from(fee_input.fair_l2_gas_price) - * (tx_gas_per_pubdata_limit - U256::from(1u32)); - - fee_input.fair_pubdata_price = new_fair_pubdata_price.as_u64(); - } - } - - batch_fee_input -} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/vm.rs b/core/lib/multivm/src/versions/vm_1_4_1/vm.rs index d87b8d96586c..5684c8821abb 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/vm.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/vm.rs @@ -16,7 +16,7 @@ use crate::{ }, vm_1_4_1::{ bootloader_state::BootloaderState, - old_vm::{events::merge_events, history_recorder::HistoryEnabled}, + old_vm::events::merge_events, tracers::dispatcher::TracerDispatcher, types::internals::{new_vm_state, VmSnapshot, ZkSyncVmState}, }, @@ -187,7 +187,7 @@ impl VmInterface for Vm { } /// Methods of vm, which required some history manipulations -impl VmInterfaceHistoryEnabled for Vm { +impl VmInterfaceHistoryEnabled for Vm { /// Create snapshot of current vm state and push it into the memory fn make_snapshot(&mut self) { self.make_snapshot_inner() diff --git a/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs b/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs index 0c836f64097f..d5d61aceafcf 100644 --- a/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs +++ b/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs @@ -20,7 +20,7 @@ use crate::{ impl Vm { pub(crate) fn inspect_inner( &mut self, - dispatcher: TracerDispatcher, + dispatcher: TracerDispatcher, execution_mode: VmExecutionMode, custom_pubdata_tracer: Option>, ) -> VmExecutionResultAndLogs { @@ -44,14 +44,14 @@ impl Vm { /// Collect the result from the default tracers. fn inspect_and_collect_results( &mut self, - dispatcher: TracerDispatcher, + dispatcher: TracerDispatcher, execution_mode: VmExecutionMode, with_refund_tracer: bool, custom_pubdata_tracer: Option>, ) -> (VmExecutionStopReason, VmExecutionResultAndLogs) { let refund_tracers = with_refund_tracer.then_some(RefundsTracer::new(self.batch_env.clone())); - let mut tx_tracer: DefaultExecutionTracer = DefaultExecutionTracer::new( + let mut tx_tracer: DefaultExecutionTracer = DefaultExecutionTracer::new( self.system_env.default_validation_computational_gas_limit, execution_mode, dispatcher, @@ -104,7 +104,7 @@ impl Vm { /// Execute vm with given tracers until the stop reason is reached. fn execute_with_default_tracer( &mut self, - tracer: &mut DefaultExecutionTracer, + tracer: &mut DefaultExecutionTracer, ) -> VmExecutionStopReason { tracer.initialize_tracer(&mut self.state); let result = loop { diff --git a/core/lib/multivm/src/versions/vm_latest/implementation/gas.rs b/core/lib/multivm/src/versions/vm_latest/implementation/gas.rs index 13932dd3c382..184430568cbc 100644 --- a/core/lib/multivm/src/versions/vm_latest/implementation/gas.rs +++ b/core/lib/multivm/src/versions/vm_latest/implementation/gas.rs @@ -9,7 +9,7 @@ use crate::{ impl Vm { pub(crate) fn calculate_computational_gas_used( &self, - tracer: &DefaultExecutionTracer, + tracer: &DefaultExecutionTracer, gas_remaining_before: u32, spent_pubdata_counter_before: u32, ) -> u32 { diff --git a/core/lib/multivm/src/versions/vm_latest/implementation/statistics.rs b/core/lib/multivm/src/versions/vm_latest/implementation/statistics.rs index 3e969d951b51..f0984d02dc18 100644 --- a/core/lib/multivm/src/versions/vm_latest/implementation/statistics.rs +++ b/core/lib/multivm/src/versions/vm_latest/implementation/statistics.rs @@ -18,7 +18,7 @@ impl Vm { &self, timestamp_initial: Timestamp, cycles_initial: u32, - tracer: &DefaultExecutionTracer, + tracer: &DefaultExecutionTracer, gas_remaining_before: u32, gas_remaining_after: u32, spent_pubdata_counter_before: u32, diff --git a/core/lib/multivm/src/versions/vm_latest/tests/tester/inner_state.rs b/core/lib/multivm/src/versions/vm_latest/tests/tester/inner_state.rs index dbe0afa33fa1..829aa93b13da 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/tester/inner_state.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/tester/inner_state.rs @@ -79,7 +79,7 @@ pub(crate) struct VmInstanceInnerState { impl Vm { // Dump inner state of the VM. - pub(crate) fn dump_inner_state(&self) -> VmInstanceInnerState { + pub(crate) fn dump_inner_state(&self) -> VmInstanceInnerState { let event_sink = self.state.event_sink.clone(); let precompile_processor_state = PrecompileProcessorTestInnerState { timestamp_history: self.state.precompiles_processor.timestamp_history.clone(), diff --git a/core/lib/multivm/src/versions/vm_latest/utils/fee.rs b/core/lib/multivm/src/versions/vm_latest/utils/fee.rs index ea4de7204434..c17e585330c9 100644 --- a/core/lib/multivm/src/versions/vm_latest/utils/fee.rs +++ b/core/lib/multivm/src/versions/vm_latest/utils/fee.rs @@ -1,8 +1,5 @@ //! Utility functions for vm -use zksync_types::{ - fee_model::{BatchFeeInput, PubdataIndependentBatchFeeModelInput}, - U256, -}; +use zksync_types::fee_model::PubdataIndependentBatchFeeModelInput; use zksync_utils::ceil_div; use crate::vm_latest::{constants::MAX_GAS_PER_PUBDATA_BYTE, L1BatchEnv}; @@ -37,34 +34,3 @@ pub(crate) fn get_batch_base_fee(l1_batch_env: &L1BatchEnv) -> u64 { derive_base_fee_and_gas_per_pubdata(l1_batch_env.fee_input.into_pubdata_independent()); base_fee } - -/// Changes the fee model output so that the expected gas per pubdata is smaller than or the `tx_gas_per_pubdata_limit`. -/// This function expects that the currently expected gas per pubdata is greater than the `tx_gas_per_pubdata_limit`. -pub(crate) fn adjust_pubdata_price_for_tx( - mut batch_fee_input: BatchFeeInput, - tx_gas_per_pubdata_limit: U256, -) -> BatchFeeInput { - match &mut batch_fee_input { - BatchFeeInput::L1Pegged(fee_input) => { - // `gasPerPubdata = ceil(17 * l1gasprice / fair_l2_gas_price)` - // `gasPerPubdata <= 17 * l1gasprice / fair_l2_gas_price + 1` - // `fair_l2_gas_price(gasPerPubdata - 1) / 17 <= l1gasprice` - let new_l1_gas_price = U256::from(fee_input.fair_l2_gas_price) - * (tx_gas_per_pubdata_limit - U256::from(1u32)) - / U256::from(17); - - fee_input.l1_gas_price = new_l1_gas_price.as_u64(); - } - BatchFeeInput::PubdataIndependent(fee_input) => { - // `gasPerPubdata = ceil(fair_pubdata_price / fair_l2_gas_price)` - // `gasPerPubdata <= fair_pubdata_price / fair_l2_gas_price + 1` - // `fair_l2_gas_price(gasPerPubdata - 1) <= fair_pubdata_price` - let new_fair_pubdata_price = U256::from(fee_input.fair_l2_gas_price) - * (tx_gas_per_pubdata_limit - U256::from(1u32)); - - fee_input.fair_pubdata_price = new_fair_pubdata_price.as_u64(); - } - } - - batch_fee_input -} diff --git a/core/lib/multivm/src/versions/vm_latest/vm.rs b/core/lib/multivm/src/versions/vm_latest/vm.rs index f570bdac72ee..a2257f96b5c3 100644 --- a/core/lib/multivm/src/versions/vm_latest/vm.rs +++ b/core/lib/multivm/src/versions/vm_latest/vm.rs @@ -29,7 +29,7 @@ use crate::{ pub struct Vm { pub(crate) bootloader_state: BootloaderState, // Current state and oracles of virtual machine - pub(crate) state: ZkSyncVmState, + pub(crate) state: ZkSyncVmState, pub(crate) storage: StoragePtr, pub(crate) system_env: SystemEnv, pub(crate) batch_env: L1BatchEnv, @@ -39,7 +39,7 @@ pub struct Vm { } impl VmInterface for Vm { - type TracerDispatcher = TracerDispatcher; + type TracerDispatcher = TracerDispatcher; fn new(batch_env: L1BatchEnv, system_env: SystemEnv, storage: StoragePtr) -> Self { let (state, bootloader_state) = new_vm_state(storage.clone(), &system_env, &batch_env); diff --git a/core/lib/multivm/src/vm_instance.rs b/core/lib/multivm/src/vm_instance.rs index a742a65f73a4..cbea46649284 100644 --- a/core/lib/multivm/src/vm_instance.rs +++ b/core/lib/multivm/src/vm_instance.rs @@ -20,7 +20,8 @@ pub enum VmInstance { VmVirtualBlocks(crate::vm_virtual_blocks::Vm), VmVirtualBlocksRefundsEnhancement(crate::vm_refunds_enhancement::Vm), VmBoojumIntegration(crate::vm_boojum_integration::Vm), - Vm1_4_1(crate::vm_latest::Vm), + Vm1_4_1(crate::vm_1_4_1::Vm), + Vm1_4_2(crate::vm_latest::Vm), } macro_rules! dispatch_vm { @@ -33,6 +34,7 @@ macro_rules! dispatch_vm { VmInstance::VmVirtualBlocksRefundsEnhancement(vm) => vm.$function($($params)*), VmInstance::VmBoojumIntegration(vm) => vm.$function($($params)*), VmInstance::Vm1_4_1(vm) => vm.$function($($params)*), + VmInstance::Vm1_4_2(vm) => vm.$function($($params)*), } }; } @@ -205,9 +207,13 @@ impl VmInstance { VmInstance::VmBoojumIntegration(vm) } VmVersion::Vm1_4_1 => { - let vm = crate::vm_latest::Vm::new(l1_batch_env, system_env, storage_view); + let vm = crate::vm_1_4_1::Vm::new(l1_batch_env, system_env, storage_view); VmInstance::Vm1_4_1(vm) } + VmVersion::Vm1_4_2 => { + let vm = crate::vm_latest::Vm::new(l1_batch_env, system_env, storage_view); + VmInstance::Vm1_4_2(vm) + } } } } diff --git a/core/lib/types/src/protocol_version.rs b/core/lib/types/src/protocol_version.rs index 639ff7f6192b..5d8b982aef53 100644 --- a/core/lib/types/src/protocol_version.rs +++ b/core/lib/types/src/protocol_version.rs @@ -42,6 +42,7 @@ pub enum ProtocolVersionId { Version19, Version20, Version21, + Version22, } impl ProtocolVersionId { @@ -78,7 +79,8 @@ impl ProtocolVersionId { ProtocolVersionId::Version18 => VmVersion::VmBoojumIntegration, ProtocolVersionId::Version19 => VmVersion::VmBoojumIntegration, ProtocolVersionId::Version20 => VmVersion::Vm1_4_1, - ProtocolVersionId::Version21 => VmVersion::Vm1_4_1, + ProtocolVersionId::Version21 => VmVersion::Vm1_4_2, + ProtocolVersionId::Version22 => VmVersion::Vm1_4_2, } } @@ -764,7 +766,8 @@ impl From for VmVersion { ProtocolVersionId::Version18 => VmVersion::VmBoojumIntegration, ProtocolVersionId::Version19 => VmVersion::VmBoojumIntegration, ProtocolVersionId::Version20 => VmVersion::Vm1_4_1, - ProtocolVersionId::Version21 => VmVersion::Vm1_4_1, + ProtocolVersionId::Version21 => VmVersion::Vm1_4_2, + ProtocolVersionId::Version22 => VmVersion::Vm1_4_2, } } } diff --git a/core/lib/types/src/vm_version.rs b/core/lib/types/src/vm_version.rs index 2a4e9dc3ef2e..5fa6c76b933f 100644 --- a/core/lib/types/src/vm_version.rs +++ b/core/lib/types/src/vm_version.rs @@ -9,11 +9,12 @@ pub enum VmVersion { VmVirtualBlocksRefundsEnhancement, VmBoojumIntegration, Vm1_4_1, + Vm1_4_2, } impl VmVersion { /// Returns the latest supported VM version. pub const fn latest() -> VmVersion { - Self::Vm1_4_1 + Self::Vm1_4_2 } } diff --git a/core/lib/zksync_core/src/api_server/execution_sandbox/tracers.rs b/core/lib/zksync_core/src/api_server/execution_sandbox/tracers.rs index e6add9a9e3b1..58d573796316 100644 --- a/core/lib/zksync_core/src/api_server/execution_sandbox/tracers.rs +++ b/core/lib/zksync_core/src/api_server/execution_sandbox/tracers.rs @@ -14,7 +14,7 @@ pub(crate) enum ApiTracer { impl ApiTracer { pub fn into_boxed< S: WriteStorage, - H: HistoryMode + multivm::HistoryMode + 'static, + H: HistoryMode + multivm::HistoryMode + 'static, >( self, ) -> MultiVmTracerPointer { diff --git a/core/lib/zksync_core/src/api_server/tx_sender/mod.rs b/core/lib/zksync_core/src/api_server/tx_sender/mod.rs index ba1463038277..cceea1fa16e2 100644 --- a/core/lib/zksync_core/src/api_server/tx_sender/mod.rs +++ b/core/lib/zksync_core/src/api_server/tx_sender/mod.rs @@ -63,6 +63,8 @@ pub struct MultiVMBaseSystemContracts { pub(crate) post_allowlist_removal: BaseSystemContracts, /// Contracts to be used after the 1.4.1 upgrade pub(crate) post_1_4_1: BaseSystemContracts, + /// Contracts to be used after the 1.4.2 upgrade + pub(crate) post_1_4_2: BaseSystemContracts, } impl MultiVMBaseSystemContracts { @@ -88,7 +90,8 @@ impl MultiVMBaseSystemContracts { | ProtocolVersionId::Version17 => self.post_virtual_blocks_finish_upgrade_fix, ProtocolVersionId::Version18 => self.post_boojum, ProtocolVersionId::Version19 => self.post_allowlist_removal, - ProtocolVersionId::Version20 | ProtocolVersionId::Version21 => self.post_1_4_1, + ProtocolVersionId::Version20 => self.post_1_4_1, + ProtocolVersionId::Version21 | ProtocolVersionId::Version22 => self.post_1_4_2, } } } @@ -121,6 +124,7 @@ impl ApiContracts { post_boojum: BaseSystemContracts::estimate_gas_post_boojum(), post_allowlist_removal: BaseSystemContracts::estimate_gas_post_allowlist_removal(), post_1_4_1: BaseSystemContracts::estimate_gas_post_1_4_1(), + post_1_4_2: BaseSystemContracts::estimate_gas_post_1_4_2(), }, eth_call: MultiVMBaseSystemContracts { pre_virtual_blocks: BaseSystemContracts::playground_pre_virtual_blocks(), @@ -130,6 +134,7 @@ impl ApiContracts { post_boojum: BaseSystemContracts::playground_post_boojum(), post_allowlist_removal: BaseSystemContracts::playground_post_allowlist_removal(), post_1_4_1: BaseSystemContracts::playground_post_1_4_1(), + post_1_4_2: BaseSystemContracts::playground_post_1_4_2(), }, } } diff --git a/core/tests/ts-integration/tests/api/web3.test.ts b/core/tests/ts-integration/tests/api/web3.test.ts index 185c9d3dd079..8cdde989a9e3 100644 --- a/core/tests/ts-integration/tests/api/web3.test.ts +++ b/core/tests/ts-integration/tests/api/web3.test.ts @@ -729,12 +729,24 @@ describe('web3 API compatibility tests', () => { let latestBlock = await alice.provider.getBlock('latest'); // Check API returns identical logs by block number and block hash. - const getLogsByNumber = await alice.provider.getLogs({ - fromBlock: latestBlock.number, - toBlock: latestBlock.number + // Logs can have different `l1BatchNumber` field though, + // if L1 batch was sealed in between API requests are processed. + const getLogsByNumber = ( + await alice.provider.getLogs({ + fromBlock: latestBlock.number, + toBlock: latestBlock.number + }) + ).map((x) => { + x.l1BatchNumber = 0; // Set bogus value. + return x; }); - const getLogsByHash = await alice.provider.getLogs({ - blockHash: latestBlock.hash + const getLogsByHash = ( + await alice.provider.getLogs({ + blockHash: latestBlock.hash + }) + ).map((x) => { + x.l1BatchNumber = 0; // Set bogus value. + return x; }); await expect(getLogsByNumber).toEqual(getLogsByHash); diff --git a/etc/multivm_bootloaders/vm_1_4_2/fee_estimate.yul/fee_estimate.yul.zbin b/etc/multivm_bootloaders/vm_1_4_2/fee_estimate.yul/fee_estimate.yul.zbin new file mode 100644 index 000000000000..a020cd118c7a Binary files /dev/null and b/etc/multivm_bootloaders/vm_1_4_2/fee_estimate.yul/fee_estimate.yul.zbin differ diff --git a/etc/multivm_bootloaders/vm_1_4_2/gas_test.yul/gas_test.yul.zbin b/etc/multivm_bootloaders/vm_1_4_2/gas_test.yul/gas_test.yul.zbin new file mode 100644 index 000000000000..ad090f3d214f Binary files /dev/null and b/etc/multivm_bootloaders/vm_1_4_2/gas_test.yul/gas_test.yul.zbin differ diff --git a/etc/multivm_bootloaders/vm_1_4_2/playground_batch.yul/playground_batch.yul.zbin b/etc/multivm_bootloaders/vm_1_4_2/playground_batch.yul/playground_batch.yul.zbin new file mode 100644 index 000000000000..fc5bd1542439 Binary files /dev/null and b/etc/multivm_bootloaders/vm_1_4_2/playground_batch.yul/playground_batch.yul.zbin differ diff --git a/etc/multivm_bootloaders/vm_1_4_2/proved_batch.yul/proved_batch.yul.zbin b/etc/multivm_bootloaders/vm_1_4_2/proved_batch.yul/proved_batch.yul.zbin new file mode 100644 index 000000000000..1ad3bd50502a Binary files /dev/null and b/etc/multivm_bootloaders/vm_1_4_2/proved_batch.yul/proved_batch.yul.zbin differ