Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(api): Adapt eth_getCode to EVM emulator #3073

Merged
merged 9 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ blake2 = "0.10"
chrono = "0.4"
clap = "4.2.2"
codegen = "0.2.0"
const-decoder = "0.4.0"
criterion = "0.4.0"
ctrlc = "3.1"
dashmap = "5.5.3"
Expand Down

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 16 additions & 4 deletions core/lib/dal/src/storage_web3_dal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ use zksync_utils::h256_to_u256;

use crate::{models::storage_block::ResolvedL1BatchForL2Block, Core, CoreDal};

/// Raw bytecode information returned by [`StorageWeb3Dal::get_contract_code_unchecked()`].
#[derive(Debug)]
pub struct RawBytecode {
pub bytecode_hash: H256,
pub bytecode: Vec<u8>,
}

#[derive(Debug)]
pub struct StorageWeb3Dal<'a, 'c> {
pub(crate) storage: &'a mut Connection<'c, Core>,
Expand Down Expand Up @@ -234,16 +241,17 @@ impl StorageWeb3Dal<'_, '_> {
&mut self,
address: Address,
block_number: L2BlockNumber,
) -> DalResult<Option<Vec<u8>>> {
) -> DalResult<Option<RawBytecode>> {
let hashed_key = get_code_key(&address).hashed_key();
let row = sqlx::query!(
r#"
SELECT
bytecode_hash,
bytecode
FROM
(
SELECT
*
value
FROM
storage_logs
WHERE
Expand All @@ -254,7 +262,7 @@ impl StorageWeb3Dal<'_, '_> {
storage_logs.operation_number DESC
LIMIT
1
) t
) deploy_log
JOIN factory_deps ON value = factory_deps.bytecode_hash
WHERE
value != $3
Expand All @@ -268,7 +276,11 @@ impl StorageWeb3Dal<'_, '_> {
.with_arg("block_number", &block_number)
.fetch_optional(self.storage)
.await?;
Ok(row.map(|row| row.bytecode))

Ok(row.map(|row| RawBytecode {
bytecode_hash: H256::from_slice(&row.bytecode_hash),
bytecode: row.bytecode,
}))
}

/// Given bytecode hash, returns bytecode and L2 block number at which it was inserted.
Expand Down
11 changes: 7 additions & 4 deletions core/lib/multivm/src/versions/vm_latest/tests/evm_emulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ use zksync_types::{
utils::{key_for_eth_balance, storage_key_for_eth_balance},
AccountTreeId, Address, Execute, StorageKey, H256, U256,
};
use zksync_utils::{be_words_to_bytes, bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256};
use zksync_utils::{
be_words_to_bytes,
bytecode::{hash_bytecode, hash_evm_bytecode},
bytes_to_be_words, h256_to_u256,
};

use crate::{
interface::{
Expand All @@ -21,7 +25,6 @@ use crate::{
versions::testonly::default_system_env,
vm_latest::{
tests::tester::{VmTester, VmTesterBuilder},
utils::hash_evm_bytecode,
HistoryEnabled,
},
};
Expand Down Expand Up @@ -87,7 +90,7 @@ impl EvmTestBuilder {
let mut storage = self.storage;
let mut system_env = default_system_env();
if self.deploy_emulator {
let evm_bytecode: Vec<_> = (0..=u8::MAX).collect();
let evm_bytecode: Vec<_> = (0..32).collect();
let evm_bytecode_hash = hash_evm_bytecode(&evm_bytecode);
storage.set_value(
get_known_code_key(&evm_bytecode_hash),
Expand Down Expand Up @@ -142,7 +145,7 @@ fn tracing_evm_contract_deployment() {
.build();
let account = &mut vm.rich_accounts[0];

let args = [Token::Bytes((0..=u8::MAX).collect())];
let args = [Token::Bytes((0..32).collect())];
let evm_bytecode = ethabi::encode(&args);
let expected_bytecode_hash = hash_evm_bytecode(&evm_bytecode);
let execute = Execute::for_deploy(expected_bytecode_hash, vec![0; 32], &args);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,14 @@ use zk_evm_1_5_0::{
},
};
use zksync_types::{CONTRACT_DEPLOYER_ADDRESS, KNOWN_CODES_STORAGE_ADDRESS};
use zksync_utils::{bytes_to_be_words, h256_to_u256};
use zksync_utils::{bytecode::hash_evm_bytecode, bytes_to_be_words, h256_to_u256};
use zksync_vm_interface::storage::StoragePtr;

use super::{traits::VmTracer, utils::read_pointer};
use crate::{
interface::{storage::WriteStorage, tracer::TracerExecutionStatus},
tracers::dynamic::vm_1_5_0::DynTracer,
vm_latest::{
utils::hash_evm_bytecode, BootloaderState, HistoryMode, SimpleMemory, ZkSyncVmState,
},
vm_latest::{BootloaderState, HistoryMode, SimpleMemory, ZkSyncVmState},
};

/// Tracer responsible for collecting information about EVM deploys and providing those
Expand Down
22 changes: 1 addition & 21 deletions core/lib/multivm/src/versions/vm_latest/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
//! Utility functions for the VM.

use once_cell::sync::Lazy;
use zk_evm_1_5_0::{
aux_structures::MemoryPage,
sha2,
zkevm_opcode_defs::{BlobSha256Format, VersionedHashLen32},
};
use zk_evm_1_5_0::aux_structures::MemoryPage;
use zksync_types::{H256, KNOWN_CODES_STORAGE_ADDRESS};
use zksync_vm_interface::VmEvent;

Expand All @@ -15,22 +11,6 @@ pub(crate) mod logs;
pub mod overhead;
pub mod transaction_encoding;

pub(crate) fn hash_evm_bytecode(bytecode: &[u8]) -> H256 {
use sha2::{Digest, Sha256};
let mut hasher = Sha256::new();
let len = bytecode.len() as u16;
hasher.update(bytecode);
let result = hasher.finalize();

let mut output = [0u8; 32];
output[..].copy_from_slice(result.as_slice());
output[0] = BlobSha256Format::VERSION_BYTE;
output[1] = 0;
output[2..4].copy_from_slice(&len.to_be_bytes());

H256(output)
}

pub const fn heap_page_from_base(base: MemoryPage) -> MemoryPage {
MemoryPage(base.0 + 2)
}
Expand Down
61 changes: 61 additions & 0 deletions core/lib/utils/src/bytecode.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// FIXME: move to basic_types?

use zk_evm::k256::sha2::{Digest, Sha256};
use zksync_basic_types::H256;

use crate::bytes_to_chunks;
Expand Down Expand Up @@ -40,6 +41,7 @@ pub fn validate_bytecode(code: &[u8]) -> Result<(), InvalidBytecodeError> {
Ok(())
}

/// Hashes the provided EraVM bytecode.
pub fn hash_bytecode(code: &[u8]) -> H256 {
let chunked_code = bytes_to_chunks(code);
let hash = zk_evm::zkevm_opcode_defs::utils::bytecode_to_code_hash(&chunked_code)
slowli marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -55,3 +57,62 @@ pub fn bytecode_len_in_words(bytecodehash: &H256) -> u16 {
pub fn bytecode_len_in_bytes(bytecodehash: H256) -> usize {
bytecode_len_in_words(&bytecodehash) as usize * 32
}

/// Bytecode marker encoded in the first byte of the bytecode hash.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum BytecodeMarker {
/// EraVM bytecode marker (1).
EraVm = 1,
/// EVM bytecode marker (2).
Evm = 2,
}

impl BytecodeMarker {
/// Parses a marker from the bytecode hash.
pub fn new(bytecode_hash: H256) -> Option<Self> {
Some(match bytecode_hash.as_bytes()[0] {
val if val == Self::EraVm as u8 => Self::EraVm,
val if val == Self::Evm as u8 => Self::Evm,
_ => return None,
})
}
}

/// Hashes the provided EVM bytecode. The bytecode must be padded to an odd number of 32-byte words;
/// bytecodes stored in the known codes storage satisfy this requirement automatically.
pub fn hash_evm_bytecode(bytecode: &[u8]) -> H256 {
validate_bytecode(bytecode).expect("invalid EVM bytecode");

let mut hasher = Sha256::new();
let len = bytecode.len() as u16;
hasher.update(bytecode);
let result = hasher.finalize();

let mut output = [0u8; 32];
output[..].copy_from_slice(result.as_slice());
output[0] = BytecodeMarker::Evm as u8;
output[1] = 0;
output[2..4].copy_from_slice(&len.to_be_bytes());

H256(output)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn bytecode_markers_are_valid() {
let bytecode_hash = hash_bytecode(&[0; 32]);
assert_eq!(
BytecodeMarker::new(bytecode_hash),
Some(BytecodeMarker::EraVm)
);
let bytecode_hash = hash_evm_bytecode(&[0; 32]);
assert_eq!(
BytecodeMarker::new(bytecode_hash),
Some(BytecodeMarker::Evm)
);
}
}
1 change: 1 addition & 0 deletions core/node/api_server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,5 @@ zksync_node_genesis.workspace = true
zksync_node_test_utils.workspace = true

assert_matches.workspace = true
const-decoder.workspace = true
test-casing.workspace = true
25 changes: 25 additions & 0 deletions core/node/api_server/src/testonly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use std::{collections::HashMap, iter};

use const_decoder::Decoder;
use zk_evm_1_5_0::zkevm_opcode_defs::decoding::{EncodingModeProduction, VmEncodingMode};
use zksync_contracts::{
eth_contract, get_loadnext_contract, load_contract, read_bytecode,
Expand All @@ -26,6 +27,30 @@ use zksync_types::{
};
use zksync_utils::{address_to_u256, u256_to_h256};

pub(crate) const RAW_EVM_BYTECODE: &[u8] = &const_decoder::decode!(
Decoder::Hex,
b"00000000000000000000000000000000000000000000000000000000000001266080604052348015\
600e575f80fd5b50600436106030575f3560e01c8063816898ff146034578063fb5343f314604c57\
5b5f80fd5b604a60048036038101906046919060a6565b6066565b005b6052606f565b604051605d\
919060d9565b60405180910390f35b805f8190555050565b5f5481565b5f80fd5b5f819050919050\
565b6088816078565b81146091575f80fd5b50565b5f8135905060a0816081565b92915050565b5f\
6020828403121560b85760b76074565b5b5f60c3848285016094565b91505092915050565b60d381\
6078565b82525050565b5f60208201905060ea5f83018460cc565b9291505056fea2646970667358\
221220caca1247066da378f2ec77c310f2ae51576272367b4fa11cc4350af4e9ce4d0964736f6c63\
4300081a00330000000000000000000000000000000000000000000000000000"
);
pub(crate) const PROCESSED_EVM_BYTECODE: &[u8] = &const_decoder::decode!(
Decoder::Hex,
b"6080604052348015600e575f80fd5b50600436106030575f3560e01c8063816898ff146034578063\
fb5343f314604c575b5f80fd5b604a60048036038101906046919060a6565b6066565b005b605260\
6f565b604051605d919060d9565b60405180910390f35b805f8190555050565b5f5481565b5f80fd\
5b5f819050919050565b6088816078565b81146091575f80fd5b50565b5f8135905060a081608156\
5b92915050565b5f6020828403121560b85760b76074565b5b5f60c3848285016094565b91505092\
915050565b60d3816078565b82525050565b5f60208201905060ea5f83018460cc565b9291505056\
fea2646970667358221220caca1247066da378f2ec77c310f2ae51576272367b4fa11cc4350af4e9\
ce4d0964736f6c634300081a0033"
);

const EXPENSIVE_CONTRACT_PATH: &str =
"etc/contracts-test-data/artifacts-zk/contracts/expensive/expensive.sol/Expensive.json";
const PRECOMPILES_CONTRACT_PATH: &str =
Expand Down
Loading
Loading