diff --git a/core/lib/basic_types/src/bytecode.rs b/core/lib/basic_types/src/bytecode.rs index 585ba0ef8c88..cb6b54fcf3ce 100644 --- a/core/lib/basic_types/src/bytecode.rs +++ b/core/lib/basic_types/src/bytecode.rs @@ -10,6 +10,8 @@ //! Both bytecode kinds are right-padded to consist of an integer, odd number of 32-byte words. All methods //! in this module operate on padded bytecodes unless explicitly specified otherwise. +use std::iter; + use anyhow::Context as _; use sha2::{Digest, Sha256}; @@ -68,21 +70,31 @@ pub struct BytecodeHash(H256); impl BytecodeHash { /// Hashes the provided EraVM bytecode. pub fn for_bytecode(bytecode: &[u8]) -> Self { - Self::for_generic_bytecode(BytecodeMarker::EraVm, bytecode) + Self::for_generic_bytecode(BytecodeMarker::EraVm, bytecode, bytecode.len()) } /// Hashes the provided padded EVM bytecode. - pub fn for_evm_bytecode(bytecode: &[u8]) -> Self { - Self::for_generic_bytecode(BytecodeMarker::Evm, bytecode) + pub fn for_evm_bytecode(raw_bytecode_len: usize, bytecode: &[u8]) -> Self { + Self::for_generic_bytecode(BytecodeMarker::Evm, bytecode, raw_bytecode_len) + } + + /// Hashes the provided raw EVM bytecode. + pub fn for_raw_evm_bytecode(bytecode: &[u8]) -> Self { + let padded_evm_bytecode = pad_evm_bytecode(bytecode); + Self::for_evm_bytecode(bytecode.len(), &padded_evm_bytecode) } - fn for_generic_bytecode(kind: BytecodeMarker, bytecode: &[u8]) -> Self { + fn for_generic_bytecode( + kind: BytecodeMarker, + bytecode: &[u8], + bytecode_len_in_bytes: usize, + ) -> Self { validate_bytecode(bytecode).expect("invalid bytecode"); let mut hasher = Sha256::new(); let len = match kind { - BytecodeMarker::EraVm => (bytecode.len() / 32) as u16, - BytecodeMarker::Evm => bytecode.len() as u16, + BytecodeMarker::EraVm => (bytecode_len_in_bytes / 32) as u16, + BytecodeMarker::Evm => bytecode_len_in_bytes as u16, }; hasher.update(bytecode); let result = hasher.finalize(); @@ -157,23 +169,22 @@ impl BytecodeMarker { } /// Removes padding from an EVM bytecode, returning the original EVM bytecode. -pub fn trim_padded_evm_bytecode(raw: &[u8]) -> anyhow::Result<&[u8]> { +pub fn trim_padded_evm_bytecode(bytecode_hash: BytecodeHash, raw: &[u8]) -> anyhow::Result<&[u8]> { + if bytecode_hash.marker() != BytecodeMarker::Evm { + anyhow::bail!("only EVM bytecode hashes allowed") + } validate_bytecode(raw).context("bytecode fails basic validity checks")?; - // EVM bytecodes are prefixed with a big-endian `U256` bytecode length. - let bytecode_len_bytes = raw.get(..32).context("length < 32")?; - let bytecode_len = U256::from_big_endian(bytecode_len_bytes); - let bytecode_len: usize = bytecode_len - .try_into() - .map_err(|_| anyhow::anyhow!("length ({bytecode_len}) overflow"))?; - let bytecode = raw.get(32..(32 + bytecode_len)).with_context(|| { + // Actual raw unpadded EVM bytecode length is encoded in bytecode hash + let bytecode_len: usize = bytecode_hash.len_in_bytes(); + let bytecode = raw.get(0..bytecode_len).with_context(|| { format!( - "prefixed length ({bytecode_len}) exceeds real length ({})", - raw.len() - 32 + "encoded length ({bytecode_len}) exceeds real length ({})", + raw.len() ) })?; // Since slicing above succeeded, this one is safe. - let padding = &raw[(32 + bytecode_len)..]; + let padding = &raw[bytecode_len..]; anyhow::ensure!( padding.iter().all(|&b| b == 0), "bytecode padding contains non-zero bytes" @@ -181,22 +192,42 @@ pub fn trim_padded_evm_bytecode(raw: &[u8]) -> anyhow::Result<&[u8]> { Ok(bytecode) } +/// Pads an EVM bytecode in the same ways it's done by system contracts. +pub fn pad_evm_bytecode(deployed_bytecode: &[u8]) -> Vec { + let mut padded = Vec::with_capacity(deployed_bytecode.len()); + padded.extend_from_slice(deployed_bytecode); + + // Pad to the 32-byte word boundary. + if padded.len() % 32 != 0 { + padded.extend(iter::repeat(0).take(32 - padded.len() % 32)); + } + assert_eq!(padded.len() % 32, 0); + + // Pad to contain the odd number of words. + if (padded.len() / 32) % 2 != 1 { + padded.extend_from_slice(&[0; 32]); + } + assert_eq!((padded.len() / 32) % 2, 1); + padded +} + #[doc(hidden)] // only useful for tests pub mod testonly { use const_decoder::Decoder; - pub const RAW_EVM_BYTECODE: &[u8] = &const_decoder::decode!( + pub const PADDED_EVM_BYTECODE: &[u8] = &const_decoder::decode!( Decoder::Hex, - b"00000000000000000000000000000000000000000000000000000000000001266080604052348015\ - 600e575f80fd5b50600436106030575f3560e01c8063816898ff146034578063fb5343f314604c57\ - 5b5f80fd5b604a60048036038101906046919060a6565b6066565b005b6052606f565b604051605d\ - 919060d9565b60405180910390f35b805f8190555050565b5f5481565b5f80fd5b5f819050919050\ - 565b6088816078565b81146091575f80fd5b50565b5f8135905060a0816081565b92915050565b5f\ - 6020828403121560b85760b76074565b5b5f60c3848285016094565b91505092915050565b60d381\ - 6078565b82525050565b5f60208201905060ea5f83018460cc565b9291505056fea2646970667358\ - 221220caca1247066da378f2ec77c310f2ae51576272367b4fa11cc4350af4e9ce4d0964736f6c63\ - 4300081a00330000000000000000000000000000000000000000000000000000" + b"6080604052348015600e575f80fd5b50600436106030575f3560e01c8063816898ff146034578063\ + fb5343f314604c575b5f80fd5b604a60048036038101906046919060a6565b6066565b005b605260\ + 6f565b604051605d919060d9565b60405180910390f35b805f8190555050565b5f5481565b5f80fd\ + 5b5f819050919050565b6088816078565b81146091575f80fd5b50565b5f8135905060a081608156\ + 5b92915050565b5f6020828403121560b85760b76074565b5b5f60c3848285016094565b91505092\ + 915050565b60d3816078565b82525050565b5f60208201905060ea5f83018460cc565b9291505056\ + fea2646970667358221220caca1247066da378f2ec77c310f2ae51576272367b4fa11cc4350af4e9\ + ce4d0964736f6c634300081a00330000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000" ); + pub const PROCESSED_EVM_BYTECODE: &[u8] = &const_decoder::decode!( Decoder::Hex, b"6080604052348015600e575f80fd5b50600436106030575f3560e01c8063816898ff146034578063\ @@ -213,7 +244,7 @@ pub mod testonly { #[cfg(test)] mod tests { use super::{ - testonly::{PROCESSED_EVM_BYTECODE, RAW_EVM_BYTECODE}, + testonly::{PADDED_EVM_BYTECODE, PROCESSED_EVM_BYTECODE}, *, }; @@ -223,14 +254,20 @@ mod tests { assert_eq!(bytecode_hash.marker(), BytecodeMarker::EraVm); assert_eq!(bytecode_hash.len_in_bytes(), 32); - let bytecode_hash = BytecodeHash::for_evm_bytecode(&[0; 32]); + let bytecode_hash = BytecodeHash::for_raw_evm_bytecode(&[0; 32]); + assert_eq!(bytecode_hash.marker(), BytecodeMarker::Evm); + assert_eq!(bytecode_hash.len_in_bytes(), 32); + + let bytecode_hash = BytecodeHash::for_evm_bytecode(32, &[0; 96]); assert_eq!(bytecode_hash.marker(), BytecodeMarker::Evm); assert_eq!(bytecode_hash.len_in_bytes(), 32); } #[test] fn preparing_evm_bytecode() { - let prepared = trim_padded_evm_bytecode(RAW_EVM_BYTECODE).unwrap(); + let bytecode_hash = + BytecodeHash::for_evm_bytecode(PROCESSED_EVM_BYTECODE.len(), &PADDED_EVM_BYTECODE); + let prepared = trim_padded_evm_bytecode(bytecode_hash, PADDED_EVM_BYTECODE).unwrap(); assert_eq!(prepared, PROCESSED_EVM_BYTECODE); } } diff --git a/core/lib/contract_verifier/src/lib.rs b/core/lib/contract_verifier/src/lib.rs index 284d9921a674..43da4127b809 100644 --- a/core/lib/contract_verifier/src/lib.rs +++ b/core/lib/contract_verifier/src/lib.rs @@ -14,7 +14,7 @@ use tokio::time; use zksync_dal::{contract_verification_dal::DeployedContractData, ConnectionPool, Core, CoreDal}; use zksync_queued_job_processor::{async_trait, JobProcessor}; use zksync_types::{ - bytecode::{trim_padded_evm_bytecode, BytecodeMarker}, + bytecode::{trim_padded_evm_bytecode, BytecodeHash, BytecodeMarker}, contract_verification_api::{ self as api, CompilationArtifacts, VerificationIncomingRequest, VerificationInfo, VerificationRequest, @@ -257,8 +257,12 @@ impl ContractVerifier { let deployed_bytecode = match bytecode_marker { BytecodeMarker::EraVm => deployed_contract.bytecode.as_slice(), - BytecodeMarker::Evm => trim_padded_evm_bytecode(&deployed_contract.bytecode) - .context("invalid stored EVM bytecode")?, + BytecodeMarker::Evm => trim_padded_evm_bytecode( + BytecodeHash::try_from(deployed_contract.bytecode_hash) + .context("Invalid bytecode hash")?, + &deployed_contract.bytecode, + ) + .context("invalid stored EVM bytecode")?, }; if artifacts.deployed_bytecode() != deployed_bytecode { diff --git a/core/lib/contract_verifier/src/tests/mod.rs b/core/lib/contract_verifier/src/tests/mod.rs index f66732675ce6..2ffb51ceb30a 100644 --- a/core/lib/contract_verifier/src/tests/mod.rs +++ b/core/lib/contract_verifier/src/tests/mod.rs @@ -1,9 +1,6 @@ //! Tests for the contract verifier. -use std::{ - collections::{HashMap, HashSet}, - iter, -}; +use std::collections::{HashMap, HashSet}; use test_casing::{test_casing, Product}; use tokio::sync::watch; @@ -11,7 +8,7 @@ use zksync_dal::Connection; use zksync_node_test_utils::{create_l1_batch, create_l2_block}; use zksync_types::{ address_to_h256, - bytecode::BytecodeHash, + bytecode::{pad_evm_bytecode, BytecodeHash}, contract_verification_api::{CompilerVersions, SourceCodeData, VerificationIncomingRequest}, get_code_key, get_known_code_key, l2::L2Tx, @@ -114,28 +111,6 @@ impl TestContract { } } -/// Pads an EVM bytecode in the same ways it's done by system contracts. -fn pad_evm_bytecode(deployed_bytecode: &[u8]) -> Vec { - let mut padded = Vec::with_capacity(deployed_bytecode.len() + 32); - let len = U256::from(deployed_bytecode.len()); - padded.extend_from_slice(&[0; 32]); - len.to_big_endian(&mut padded); - padded.extend_from_slice(deployed_bytecode); - - // Pad to the 32-byte word boundary. - if padded.len() % 32 != 0 { - padded.extend(iter::repeat(0).take(32 - padded.len() % 32)); - } - assert_eq!(padded.len() % 32, 0); - - // Pad to contain the odd number of words. - if (padded.len() / 32) % 2 != 1 { - padded.extend_from_slice(&[0; 32]); - } - assert_eq!((padded.len() / 32) % 2, 1); - padded -} - async fn mock_deployment( storage: &mut Connection<'_, Core>, address: Address, @@ -163,7 +138,7 @@ async fn mock_evm_deployment( factory_deps: vec![], }; let bytecode = pad_evm_bytecode(deployed_bytecode); - let bytecode_hash = BytecodeHash::for_evm_bytecode(&bytecode).value(); + let bytecode_hash = BytecodeHash::for_evm_bytecode(deployed_bytecode.len(), &bytecode).value(); mock_deployment_inner(storage, address, bytecode_hash, bytecode, deployment).await; } diff --git a/core/lib/multivm/src/versions/testonly/evm_emulator.rs b/core/lib/multivm/src/versions/testonly/evm_emulator.rs index b979efe360db..bcf6eccfdf5d 100644 --- a/core/lib/multivm/src/versions/testonly/evm_emulator.rs +++ b/core/lib/multivm/src/versions/testonly/evm_emulator.rs @@ -76,7 +76,8 @@ impl EvmTestBuilder { let mut system_env = default_system_env(); if self.deploy_emulator { let evm_bytecode: Vec<_> = (0..32).collect(); - let evm_bytecode_hash = BytecodeHash::for_evm_bytecode(&evm_bytecode).value(); + let evm_bytecode_hash = + BytecodeHash::for_evm_bytecode(evm_bytecode.len(), &evm_bytecode).value(); storage.set_value( get_known_code_key(&evm_bytecode_hash), H256::from_low_u64_be(1), @@ -131,7 +132,8 @@ pub(crate) fn test_tracing_evm_contract_deployment() { let args = [Token::Bytes((0..32).collect())]; let evm_bytecode = ethabi::encode(&args); - let expected_bytecode_hash = BytecodeHash::for_evm_bytecode(&evm_bytecode).value(); + let expected_bytecode_hash = + BytecodeHash::for_evm_bytecode(evm_bytecode.len(), &evm_bytecode).value(); let execute = Execute::for_deploy(expected_bytecode_hash, vec![0; 32], &args); let deploy_tx = account.get_l2_tx_for_execute(execute, None); let (_, vm_result) = vm @@ -148,7 +150,8 @@ pub(crate) fn test_tracing_evm_contract_deployment() { // "Deploy" a bytecode in another transaction and check that the first tx doesn't interfere with the returned `dynamic_factory_deps`. let args = [Token::Bytes((0..32).rev().collect())]; let evm_bytecode = ethabi::encode(&args); - let expected_bytecode_hash = BytecodeHash::for_evm_bytecode(&evm_bytecode).value(); + let expected_bytecode_hash = + BytecodeHash::for_evm_bytecode(evm_bytecode.len(), &evm_bytecode).value(); let execute = Execute::for_deploy(expected_bytecode_hash, vec![0; 32], &args); let deploy_tx = account.get_l2_tx_for_execute(execute, None); let (_, vm_result) = vm @@ -324,7 +327,8 @@ pub(crate) fn test_mock_emulator_with_deployment(revert: bool) { let mock_emulator_abi = &TestContract::mock_evm_emulator().abi; let new_evm_bytecode = vec![0xfe; 96]; - let new_evm_bytecode_hash = BytecodeHash::for_evm_bytecode(&new_evm_bytecode).value(); + let new_evm_bytecode_hash = + BytecodeHash::for_evm_bytecode(new_evm_bytecode.len(), &new_evm_bytecode).value(); let test_fn = mock_emulator_abi.function("testDeploymentAndCall").unwrap(); let test_tx = account.get_l2_tx_for_execute( @@ -402,7 +406,10 @@ pub(crate) fn test_mock_emulator_with_recursive_deployment() { let bytecodes: HashMap<_, _> = (0_u8..10) .map(|byte| { let bytecode = vec![byte; 32]; - (BytecodeHash::for_evm_bytecode(&bytecode).value(), bytecode) + ( + BytecodeHash::for_evm_bytecode(bytecode.len(), &bytecode).value(), + bytecode, + ) }) .collect(); let test_fn = mock_emulator_abi @@ -448,7 +455,10 @@ fn test_mock_emulator_with_partial_reverts_and_rng(rng: &mut impl let all_bytecodes: HashMap<_, _> = (0_u8..10) .map(|_| { let bytecode = vec![rng.gen(); 32]; - (BytecodeHash::for_evm_bytecode(&bytecode).value(), bytecode) + ( + BytecodeHash::for_evm_bytecode(bytecode.len(), &bytecode).value(), + bytecode, + ) }) .collect(); let should_revert: Vec<_> = (0..10).map(|_| rng.gen::()).collect(); diff --git a/core/lib/multivm/src/versions/vm_fast/tracers/evm_deploy.rs b/core/lib/multivm/src/versions/vm_fast/tracers/evm_deploy.rs index 0fbf9dec7215..1202b5b94dd2 100644 --- a/core/lib/multivm/src/versions/vm_fast/tracers/evm_deploy.rs +++ b/core/lib/multivm/src/versions/vm_fast/tracers/evm_deploy.rs @@ -37,8 +37,10 @@ pub(super) struct EvmDeployTracer { impl EvmDeployTracer { pub(super) fn new(bytecodes: DynamicBytecodes) -> Self { - let tracked_signature = - ethabi::short_signature("publishEVMBytecode", &[ethabi::ParamType::Bytes]); + let tracked_signature = ethabi::short_signature( + "publishEVMBytecode", + &[ethabi::ParamType::Uint(256), ethabi::ParamType::Bytes], + ); Self { tracked_signature, bytecodes, @@ -61,13 +63,26 @@ impl EvmDeployTracer { return; } - match ethabi::decode(&[ethabi::ParamType::Bytes], data) { + match ethabi::decode( + &[ethabi::ParamType::Uint(256), ethabi::ParamType::Bytes], + data, + ) { Ok(decoded) => { // `unwrap`s should be safe since the function signature is checked above. - let published_bytecode = decoded.into_iter().next().unwrap().into_bytes().unwrap(); - let bytecode_hash = - BytecodeHash::for_evm_bytecode(&published_bytecode).value_u256(); - self.bytecodes.insert(bytecode_hash, published_bytecode); + let mut decoded_iter = decoded.into_iter(); + let raw_bytecode_len = decoded_iter.next().unwrap().into_uint().unwrap().try_into(); + match raw_bytecode_len { + Ok(raw_bytecode_len) => { + let published_bytecode = decoded_iter.next().unwrap().into_bytes().unwrap(); + let bytecode_hash = + BytecodeHash::for_evm_bytecode(raw_bytecode_len, &published_bytecode) + .value_u256(); + self.bytecodes.insert(bytecode_hash, published_bytecode); + } + Err(err) => { + tracing::error!("Invalid bytecode len in `publishEVMBytecode` call: {err}") + } + } } Err(err) => tracing::error!("Unable to decode `publishEVMBytecode` call: {err}"), } diff --git a/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs b/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs index 2e6ab8089eb0..dd03a9427efa 100644 --- a/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs +++ b/core/lib/multivm/src/versions/vm_latest/tracers/evm_deploy_tracer.rs @@ -27,14 +27,16 @@ use crate::{ #[derive(Debug)] pub(crate) struct EvmDeployTracer { tracked_signature: [u8; 4], - pending_bytecodes: Vec>, + pending_bytecodes: Vec<(usize, Vec)>, _phantom: PhantomData, } impl EvmDeployTracer { pub(crate) fn new() -> Self { - let tracked_signature = - ethabi::short_signature("publishEVMBytecode", &[ethabi::ParamType::Bytes]); + let tracked_signature = ethabi::short_signature( + "publishEVMBytecode", + &[ethabi::ParamType::Uint(256), ethabi::ParamType::Bytes], + ); Self { tracked_signature, @@ -77,10 +79,23 @@ impl DynTracer> for EvmDeployTracer { return; } - match ethabi::decode(&[ethabi::ParamType::Bytes], data) { + match ethabi::decode( + &[ethabi::ParamType::Uint(256), ethabi::ParamType::Bytes], + data, + ) { Ok(decoded) => { - let published_bytecode = decoded.into_iter().next().unwrap().into_bytes().unwrap(); - self.pending_bytecodes.push(published_bytecode); + let mut decoded_iter = decoded.into_iter(); + let raw_bytecode_len = decoded_iter.next().unwrap().into_uint().unwrap().try_into(); + match raw_bytecode_len { + Ok(raw_bytecode_len) => { + let published_bytecode = decoded_iter.next().unwrap().into_bytes().unwrap(); + self.pending_bytecodes + .push((raw_bytecode_len, published_bytecode)); + } + Err(err) => { + tracing::error!("Invalid bytecode len in `publishEVMBytecode` call: {err}") + } + } } Err(err) => tracing::error!("Unable to decode `publishEVMBytecode` call: {err}"), } @@ -94,8 +109,9 @@ impl VmTracer for EvmDeployTracer { _bootloader_state: &mut BootloaderState, ) -> TracerExecutionStatus { let timestamp = Timestamp(state.local_state.timestamp); - for published_bytecode in mem::take(&mut self.pending_bytecodes) { - let hash = BytecodeHash::for_evm_bytecode(&published_bytecode).value_u256(); + for (raw_bytecode_len, published_bytecode) in mem::take(&mut self.pending_bytecodes) { + let hash = + BytecodeHash::for_evm_bytecode(raw_bytecode_len, &published_bytecode).value_u256(); let as_words = bytes_to_be_words(&published_bytecode); state .decommittment_processor diff --git a/core/lib/test_contracts/contracts/mock-evm/mock-evm.sol b/core/lib/test_contracts/contracts/mock-evm/mock-evm.sol index 3a7ee40db228..61cd483a5f7d 100644 --- a/core/lib/test_contracts/contracts/mock-evm/mock-evm.sol +++ b/core/lib/test_contracts/contracts/mock-evm/mock-evm.sol @@ -38,7 +38,7 @@ contract MockKnownCodeStorage { evmBytecodeHash = _bytecodeHash; } - function publishEVMBytecode(bytes calldata _bytecode) external { + function publishEVMBytecode(uint256 _bytecodeLen, bytes calldata _bytecode) external { bytes32 hash = evmBytecodeHash; require(hash != bytes32(0), "EVM bytecode hash not set"); @@ -85,7 +85,7 @@ contract MockContractDeployer { bytes calldata _input ) external payable returns (address) { KNOWN_CODE_STORAGE_CONTRACT.setEVMBytecodeHash(_salt); - KNOWN_CODE_STORAGE_CONTRACT.publishEVMBytecode(_input); + KNOWN_CODE_STORAGE_CONTRACT.publishEVMBytecode(_input.length, _input); address newAddress = address(uint160(msg.sender) + 1); ACCOUNT_CODE_STORAGE_CONTRACT.storeAccountConstructedCodeHash(newAddress, _salt); return newAddress; @@ -101,7 +101,7 @@ contract MockContractDeployer { bytes calldata _input ) external payable returns (address newAddress) { KNOWN_CODE_STORAGE_CONTRACT.setEVMBytecodeHash(_bytecodeHash); - KNOWN_CODE_STORAGE_CONTRACT.publishEVMBytecode(_input); + KNOWN_CODE_STORAGE_CONTRACT.publishEVMBytecode(_input.length, _input); bytes32 hash = keccak256( bytes.concat(CREATE2_PREFIX, bytes32(uint256(uint160(msg.sender))), _salt, _bytecodeHash) diff --git a/core/node/api_server/src/web3/namespaces/eth.rs b/core/node/api_server/src/web3/namespaces/eth.rs index 2765de2c2892..f71b66b416e0 100644 --- a/core/node/api_server/src/web3/namespaces/eth.rs +++ b/core/node/api_server/src/web3/namespaces/eth.rs @@ -6,7 +6,7 @@ use zksync_types::{ state_override::StateOverride, BlockId, BlockNumber, FeeHistory, GetLogsFilter, Transaction, TransactionId, TransactionReceipt, TransactionVariant, }, - bytecode::{trim_padded_evm_bytecode, BytecodeMarker}, + bytecode::{trim_padded_evm_bytecode, BytecodeHash, BytecodeMarker}, l2::{L2Tx, TransactionType}, transaction_request::CallRequest, u256_to_h256, @@ -404,14 +404,22 @@ impl EthNamespace { // Check if the bytecode is an EVM bytecode, and if so, pre-process it correspondingly. let marker = BytecodeMarker::new(contract_code.bytecode_hash); let prepared_bytecode = if marker == Some(BytecodeMarker::Evm) { - trim_padded_evm_bytecode(&contract_code.bytecode) - .with_context(|| { + trim_padded_evm_bytecode( + BytecodeHash::try_from(contract_code.bytecode_hash).with_context(|| { format!( - "malformed EVM bytecode at address {address:?}, hash = {:?}", + "Invalid bytecode hash at address {address:?}: {:?}", contract_code.bytecode_hash ) - })? - .to_vec() + })?, + &contract_code.bytecode, + ) + .with_context(|| { + format!( + "malformed EVM bytecode at address {address:?}, hash = {:?}", + contract_code.bytecode_hash + ) + })? + .to_vec() } else { contract_code.bytecode }; diff --git a/core/node/api_server/src/web3/tests/mod.rs b/core/node/api_server/src/web3/tests/mod.rs index f447f135917a..9c5730a23386 100644 --- a/core/node/api_server/src/web3/tests/mod.rs +++ b/core/node/api_server/src/web3/tests/mod.rs @@ -34,7 +34,7 @@ use zksync_types::{ api, block::{pack_block_info, L2BlockHasher, L2BlockHeader}, bytecode::{ - testonly::{PROCESSED_EVM_BYTECODE, RAW_EVM_BYTECODE}, + testonly::{PADDED_EVM_BYTECODE, PROCESSED_EVM_BYTECODE}, BytecodeHash, }, fee_model::{BatchFeeInput, FeeParams}, @@ -1171,14 +1171,16 @@ impl GetBytecodeTest { at_block: L2BlockNumber, address: Address, ) -> anyhow::Result<()> { - let evm_bytecode_hash = BytecodeHash::for_evm_bytecode(RAW_EVM_BYTECODE).value(); + let evm_bytecode_hash = + BytecodeHash::for_evm_bytecode(PROCESSED_EVM_BYTECODE.len(), PADDED_EVM_BYTECODE) + .value(); let code_log = StorageLog::new_write_log(get_code_key(&address), evm_bytecode_hash); connection .storage_logs_dal() .append_storage_logs(at_block, &[code_log]) .await?; - let factory_deps = HashMap::from([(evm_bytecode_hash, RAW_EVM_BYTECODE.to_vec())]); + let factory_deps = HashMap::from([(evm_bytecode_hash, PADDED_EVM_BYTECODE.to_vec())]); connection .factory_deps_dal() .insert_factory_deps(at_block, &factory_deps) diff --git a/core/node/contract_verification_server/src/tests.rs b/core/node/contract_verification_server/src/tests.rs index c5c1d88b3d0c..88b14db68733 100644 --- a/core/node/contract_verification_server/src/tests.rs +++ b/core/node/contract_verification_server/src/tests.rs @@ -54,7 +54,7 @@ async fn mock_deploy_contract( ) { let bytecode_hash = match kind { BytecodeMarker::EraVm => BytecodeHash::for_bytecode(&[0; 32]).value(), - BytecodeMarker::Evm => BytecodeHash::for_evm_bytecode(&[0; 96]).value(), + BytecodeMarker::Evm => BytecodeHash::for_evm_bytecode(0, &[0; 96]).value(), }; let deploy_log = StorageLog::new_write_log(get_code_key(&address), bytecode_hash); storage diff --git a/core/node/state_keeper/src/io/tests/mod.rs b/core/node/state_keeper/src/io/tests/mod.rs index 536efe82804a..39c9552c2fc5 100644 --- a/core/node/state_keeper/src/io/tests/mod.rs +++ b/core/node/state_keeper/src/io/tests/mod.rs @@ -447,7 +447,7 @@ async fn processing_dynamic_factory_deps_when_sealing_l2_block() { .map(|byte| { let evm_bytecode = vec![byte; 96]; ( - BytecodeHash::for_evm_bytecode(&evm_bytecode).value(), + BytecodeHash::for_raw_evm_bytecode(&evm_bytecode).value(), evm_bytecode, ) })