diff --git a/crates/ef-testing/src/evm_sequencer/account/v0.rs b/crates/ef-testing/src/evm_sequencer/account/v0.rs index 1e3c5698..bbef66a0 100644 --- a/crates/ef-testing/src/evm_sequencer/account/v0.rs +++ b/crates/ef-testing/src/evm_sequencer/account/v0.rs @@ -62,10 +62,9 @@ impl KakarotAccount { }; // Initialize the bytecode storage var. - let mut bytecode_storage = code - .into_iter() + let mut bytecode_storage = split_bytecode_to_starkfelt(code) .enumerate() - .map(|(i, byte)| (StorageKey::from(i as u64), StarkFelt::from(*byte))) + .map(|(i, bytes)| starknet_storage!("bytecode_", [StarkFelt::from(i as u32)], bytes)) .collect(); storage.append(&mut bytecode_storage); @@ -91,3 +90,12 @@ impl KakarotAccount { }) } } + +/// Splits a byte array into 16-byte chunks and converts each chunk to a StarkFelt. +pub fn split_bytecode_to_starkfelt(bytecode: &Bytes) -> impl Iterator + '_ { + bytecode.chunks(16).map(|x| { + let mut storage_value = [0u8; 16]; + storage_value[..x.len()].copy_from_slice(x); + StarkFelt::from(u128::from_be_bytes(storage_value)) + }) +} diff --git a/crates/ef-testing/src/evm_sequencer/evm_state/v0.rs b/crates/ef-testing/src/evm_sequencer/evm_state/v0.rs index 2412cb1a..0c423ed3 100644 --- a/crates/ef-testing/src/evm_sequencer/evm_state/v0.rs +++ b/crates/ef-testing/src/evm_sequencer/evm_state/v0.rs @@ -1,7 +1,6 @@ use blockifier::abi::abi_utils::{get_fee_token_var_address, get_storage_var_address}; use blockifier::abi::sierra_types::next_storage_key; use blockifier::execution::errors::EntryPointExecutionError; -use blockifier::state::errors::StateError; use blockifier::state::state_api::{State, StateReader, StateResult}; use blockifier::transaction::errors::TransactionExecutionError; use blockifier::transaction::objects::{TransactionExecutionInfo, TransactionExecutionResult}; @@ -11,7 +10,6 @@ use sequencer::execution::Execution as _; use sequencer::transaction::BroadcastedTransactionWrapper; use starknet::core::types::{BroadcastedTransaction, FieldElement}; use starknet_api::hash::StarkFelt; -use starknet_api::state::StorageKey; use super::Evm; use crate::evm_sequencer::account::{AccountType, KakarotAccount}; @@ -22,7 +20,8 @@ use crate::evm_sequencer::constants::KAKAROT_ADDRESS; use crate::evm_sequencer::constants::{CHAIN_ID, ETH_FEE_TOKEN_ADDRESS}; use crate::evm_sequencer::sequencer::KakarotSequencer; use crate::evm_sequencer::utils::{ - compute_starknet_address, split_u256, to_broadcasted_starknet_transaction, + compute_starknet_address, high_16_bytes_of_felt_to_bytes, split_u256, + to_broadcasted_starknet_transaction, }; impl Evm for KakarotSequencer { @@ -134,8 +133,7 @@ impl Evm for KakarotSequencer { /// Returns the bytecode of the given address. For an EOA, the bytecode_len_ storage variable will return 0, /// and the function will return an empty vector. For a contract account, the function will return the bytecode - /// stored in the bytecode_ storage variables. The function assumes that the bytecode is stored byte by byte, - /// starting from the storage key 0. + /// stored in the bytecode_ storage variables. The function assumes that the bytecode is stored in 16 byte big-endian chunks. fn code_at(&mut self, evm_address: &Address) -> StateResult { let starknet_address = compute_starknet_address(evm_address); @@ -148,17 +146,22 @@ impl Evm for KakarotSequencer { return Ok(Bytes::default()); } + // Assumes that the bytecode is stored in 16 byte chunks. + let num_chunks = bytecode_len / 16; let mut bytecode: Vec = Vec::new(); - for index in 0..bytecode_len { - let key = StorageKey::from(index); + for chunk_index in 0..num_chunks { + let key = get_storage_var_address("bytecode_", &[StarkFelt::from(chunk_index)]); let code = (&mut self.state).get_storage_at(starknet_address.try_into()?, key)?; - let code: FieldElement = code.into(); - bytecode.push(code.try_into().map_err(|_| { - StateError::StateReadError("FieldElement did not fit in u8".to_string()) - })?) + bytecode.append(&mut high_16_bytes_of_felt_to_bytes(&code.into(), 16).to_vec()); } + let remainder = bytecode_len % 16; + let key = get_storage_var_address("bytecode_", &[StarkFelt::from(num_chunks)]); + let code = (&mut self.state).get_storage_at(starknet_address.try_into()?, key)?; + bytecode + .append(&mut high_16_bytes_of_felt_to_bytes(&code.into(), remainder as usize).to_vec()); + Ok(Bytes::from(bytecode)) } diff --git a/crates/ef-testing/src/evm_sequencer/utils.rs b/crates/ef-testing/src/evm_sequencer/utils.rs index 9e9dd4d6..ea97d417 100644 --- a/crates/ef-testing/src/evm_sequencer/utils.rs +++ b/crates/ef-testing/src/evm_sequencer/utils.rs @@ -1,7 +1,7 @@ use super::constants::KAKAROT_ADDRESS; use super::types::felt::FeltSequencer; use bytes::BytesMut; -use reth_primitives::{Address, TransactionSigned, TxType}; +use reth_primitives::{Address, Bytes, TransactionSigned, TxType}; use revm_primitives::U256; use starknet::core::{ types::{BroadcastedInvokeTransaction, FieldElement}, @@ -57,6 +57,11 @@ pub fn split_u256(value: U256) -> [u128; 2] { ] } +/// Converts the high 16 bytes of a FieldElement to a byte array. +pub fn high_16_bytes_of_felt_to_bytes(felt: &FieldElement, len: usize) -> Bytes { + Bytes::from(&felt.to_bytes_be()[16..len + 16]) +} + /// Converts an signed transaction and a signature to a Starknet-rs transaction. pub fn to_broadcasted_starknet_transaction( transaction: &TransactionSigned, @@ -127,3 +132,49 @@ pub fn to_broadcasted_starknet_transaction( Ok(request) } + +#[cfg(test)] +mod tests { + use super::*; + + macro_rules! test_felt_to_bytes { + ($input: expr, $output: expr, $len: expr, $test_name: ident) => { + #[test] + fn $test_name() { + // Given + let felt = FieldElement::from_hex_be($input).unwrap(); + + // When + let bytes = high_16_bytes_of_felt_to_bytes(&felt, $len); + + // Then + let expected = Bytes::from($output); + assert_eq!(bytes, expected); + } + }; + } + + test_felt_to_bytes!( + "0x1234567890abcdef1234567890abcdef", + vec![ + 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, + 0xcd, 0xef + ], + 16, + test_felt_to_bytes_full + ); + + test_felt_to_bytes!( + "0x12345678900000000000000000000000", + vec![0x12, 0x34, 0x56, 0x78, 0x90], + 5, + test_felt_to_bytes_partial + ); + + test_felt_to_bytes!( + "0x12345678900000000000000000000000", + vec![], + 0, + test_felt_to_bytes_empty + ); +}