Skip to content
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

## Perf

### 2026-06-03

- Short-circuit the `KECCAK256` opcode on zero-length input by returning the precomputed `keccak256("")` constant, skipping the permutation [#6775](https://github.com/lambdaclass/ethrex/pull/6775)

### 2026-05-27

- Prefetch all BAL storage synchronously before execution [#6732](https://github.com/lambdaclass/ethrex/pull/6732)
Expand Down
8 changes: 4 additions & 4 deletions crates/blockchain/vm.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use ethrex_common::{
Address, H256, U256,
constants::EMPTY_KECCACK_HASH,
constants::EMPTY_KECCAK_HASH,
types::{AccountState, BlockHash, BlockHeader, BlockNumber, ChainConfig, Code, CodeMetadata},
};
use ethrex_crypto::keccak::keccak_hash;
Expand Down Expand Up @@ -210,7 +210,7 @@ impl VmDatabase for StoreVmDatabase {
fields(namespace = "block_execution")
)]
fn get_account_code(&self, code_hash: H256) -> Result<Code, EvmError> {
if code_hash == *EMPTY_KECCACK_HASH {
if code_hash == *EMPTY_KECCAK_HASH {
return Ok(Code::default());
}
match self.store.get_account_code(code_hash) {
Expand All @@ -229,9 +229,9 @@ impl VmDatabase for StoreVmDatabase {
fields(namespace = "block_execution")
)]
fn get_code_metadata(&self, code_hash: H256) -> Result<CodeMetadata, EvmError> {
use ethrex_common::constants::EMPTY_KECCACK_HASH;
use ethrex_common::constants::EMPTY_KECCAK_HASH;

if code_hash == *EMPTY_KECCACK_HASH {
if code_hash == *EMPTY_KECCAK_HASH {
return Ok(CodeMetadata { length: 0 });
}
match self.store.get_code_metadata(code_hash) {
Expand Down
2 changes: 1 addition & 1 deletion crates/common/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub static EMPTY_WITHDRAWALS_HASH: LazyLock<H256> = LazyLock::new(|| {
});

// Keccak256(""), represents the code hash for an account without code
pub static EMPTY_KECCACK_HASH: LazyLock<H256> = LazyLock::new(|| {
pub static EMPTY_KECCAK_HASH: LazyLock<H256> = LazyLock::new(|| {
H256::from_slice(
&hex::decode("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
.expect("Failed to decode hex from string"),
Expand Down
14 changes: 7 additions & 7 deletions crates/common/types/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use ethrex_rlp::{
};

use super::GenesisAccount;
use crate::constants::{EMPTY_KECCACK_HASH, EMPTY_TRIE_HASH};
use crate::constants::{EMPTY_KECCAK_HASH, EMPTY_TRIE_HASH};

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct Code {
Expand Down Expand Up @@ -140,7 +140,7 @@ pub struct AccountStateSlimCodec(pub AccountState);
impl Default for AccountInfo {
fn default() -> Self {
Self {
code_hash: *EMPTY_KECCACK_HASH,
code_hash: *EMPTY_KECCAK_HASH,
balance: Default::default(),
nonce: Default::default(),
}
Expand All @@ -153,7 +153,7 @@ impl Default for AccountState {
nonce: Default::default(),
balance: Default::default(),
storage_root: *EMPTY_TRIE_HASH,
code_hash: *EMPTY_KECCACK_HASH,
code_hash: *EMPTY_KECCAK_HASH,
}
}
}
Expand All @@ -162,7 +162,7 @@ impl Default for Code {
fn default() -> Self {
Self {
bytecode: Bytes::new(),
hash: *EMPTY_KECCACK_HASH,
hash: *EMPTY_KECCAK_HASH,
jump_targets: Vec::new(),
}
}
Expand Down Expand Up @@ -262,7 +262,7 @@ impl RLPEncode for AccountStateSlimCodec {
struct CodeHashCodec<'a>(&'a H256);
impl RLPEncode for CodeHashCodec<'_> {
fn encode(&self, buf: &mut dyn BufMut) {
let data = if *self.0 != *EMPTY_KECCACK_HASH {
let data = if *self.0 != *EMPTY_KECCAK_HASH {
self.0.as_bytes()
} else {
&[]
Expand Down Expand Up @@ -306,7 +306,7 @@ impl RLPDecode for AccountStateSlimCodec {
impl RLPDecode for CodeHashCodec {
fn decode_unfinished(mut rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> {
let value = match rlp.split_off_first() {
Some(0x80) => *EMPTY_KECCACK_HASH,
Some(0x80) => *EMPTY_KECCAK_HASH,
Some(0xA0) => {
let data;
(data, rlp) = rlp
Expand Down Expand Up @@ -376,7 +376,7 @@ impl Account {

impl AccountInfo {
pub fn is_empty(&self) -> bool {
self.balance.is_zero() && self.nonce == 0 && self.code_hash == *EMPTY_KECCACK_HASH
self.balance.is_zero() && self.nonce == 0 && self.code_hash == *EMPTY_KECCAK_HASH
}
}

Expand Down
6 changes: 3 additions & 3 deletions crates/common/types/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,7 @@ pub fn calc_excess_blob_gas(parent: &BlockHeader, schedule: ForkBlobSchedule, fo
#[cfg(test)]
mod test {
use super::*;
use crate::constants::EMPTY_KECCACK_HASH;
use crate::constants::EMPTY_KECCAK_HASH;
use crate::types::{BLOB_BASE_FEE_UPDATE_FRACTION, ELASTICITY_MULTIPLIER};
use ethereum_types::H160;
use hex_literal::hex;
Expand Down Expand Up @@ -951,7 +951,7 @@ mod test {
blob_gas_used: Some(0x00),
excess_blob_gas: Some(0x00),
parent_beacon_block_root: Some(H256::zero()),
requests_hash: Some(*EMPTY_KECCACK_HASH),
requests_hash: Some(*EMPTY_KECCAK_HASH),
..Default::default()
};
let block = BlockHeader {
Expand Down Expand Up @@ -995,7 +995,7 @@ mod test {
blob_gas_used: Some(0x00),
excess_blob_gas: Some(0x00),
parent_beacon_block_root: Some(H256::zero()),
requests_hash: Some(*EMPTY_KECCACK_HASH),
requests_hash: Some(*EMPTY_KECCAK_HASH),
..Default::default()
};
assert!(validate_block_header(&block, &parent_block, ELASTICITY_MULTIPLIER).is_ok());
Expand Down
6 changes: 3 additions & 3 deletions crates/common/types/block_execution_witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::rkyv_utils::H256Wrapper;
use crate::serde_utils;
use crate::types::{Block, Code, CodeMetadata};
use crate::{
constants::EMPTY_KECCACK_HASH,
constants::EMPTY_KECCAK_HASH,
types::{AccountState, AccountUpdate, BlockHeader, ChainConfig},
utils::keccak,
};
Expand Down Expand Up @@ -631,7 +631,7 @@ impl GuestProgramState {
/// include every byte of code the VM reads, and EIP-8025 stateless
/// validation requires the same.
pub fn get_account_code(&self, code_hash: H256) -> Result<Code, GuestProgramStateError> {
if code_hash == *EMPTY_KECCACK_HASH {
if code_hash == *EMPTY_KECCAK_HASH {
return Ok(Code::default());
}
self.codes_hashed
Expand All @@ -646,7 +646,7 @@ impl GuestProgramState {
&self,
code_hash: H256,
) -> Result<CodeMetadata, GuestProgramStateError> {
if code_hash == *EMPTY_KECCACK_HASH {
if code_hash == *EMPTY_KECCAK_HASH {
return Ok(CodeMetadata { length: 0 });
}
self.codes_hashed
Expand Down
4 changes: 2 additions & 2 deletions crates/networking/p2p/sync/healing/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::{
time::{Duration, Instant},
};

use ethrex_common::{H256, constants::EMPTY_KECCACK_HASH, types::AccountState};
use ethrex_common::{H256, constants::EMPTY_KECCAK_HASH, types::AccountState};
use ethrex_crypto::NativeCrypto;
use ethrex_rlp::{decode::RLPDecode, encode::RLPEncode};
use ethrex_storage::Store;
Expand Down Expand Up @@ -211,7 +211,7 @@ async fn heal_state_trie(
H256::from_slice(&meta.path.concat(&node.partial).to_bytes());

// // Collect valid code hash
if account.code_hash != *EMPTY_KECCACK_HASH {
if account.code_hash != *EMPTY_KECCAK_HASH {
code_hash_collector.add(account.code_hash);
code_hash_collector.flush_if_needed().await?;
}
Expand Down
8 changes: 4 additions & 4 deletions crates/networking/p2p/sync/snap_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use ethrex_blockchain::Blockchain;
use ethrex_common::types::{AccountState, BlockHeader, Code};
use ethrex_common::{
H256,
constants::{EMPTY_KECCACK_HASH, EMPTY_TRIE_HASH},
constants::{EMPTY_KECCAK_HASH, EMPTY_TRIE_HASH},
};
use ethrex_rlp::decode::RLPDecode;
use ethrex_storage::Store;
Expand Down Expand Up @@ -928,7 +928,7 @@ pub fn validate_bytecodes(store: Store, state_root: H256) -> bool {
.iter_accounts(state_root)
.expect("we couldn't iterate over accounts")
{
if account_state.code_hash != *EMPTY_KECCACK_HASH
if account_state.code_hash != *EMPTY_KECCAK_HASH
&& !store
.get_account_code(account_state.code_hash)
.is_ok_and(|code| code.is_some())
Expand Down Expand Up @@ -1012,7 +1012,7 @@ async fn insert_accounts(
let code_hashes_from_snapshot: Vec<H256> = account_states_snapshot
.iter()
.filter_map(|(_, state)| {
(state.code_hash != *EMPTY_KECCACK_HASH).then_some(state.code_hash)
(state.code_hash != *EMPTY_KECCAK_HASH).then_some(state.code_hash)
})
.collect();

Expand Down Expand Up @@ -1132,7 +1132,7 @@ async fn insert_accounts(
for account in iter {
let account = account.map_err(|err| SyncError::RocksDBError(err.into_string()))?;
let account_state = AccountState::decode(&account.1).map_err(SyncError::Rlp)?;
if account_state.code_hash != *EMPTY_KECCACK_HASH {
if account_state.code_hash != *EMPTY_KECCAK_HASH {
code_hash_collector.add(account_state.code_hash);
code_hash_collector.flush_if_needed().await?;
}
Expand Down
4 changes: 2 additions & 2 deletions crates/networking/rpc/types/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ mod test {
use bytes::Bytes;
use ethrex_common::{
Address, Bloom, H256, U256,
constants::EMPTY_KECCACK_HASH,
constants::EMPTY_KECCAK_HASH,
types::{EIP1559Transaction, Transaction, TxKind},
};
use std::str::FromStr;
Expand Down Expand Up @@ -170,7 +170,7 @@ mod test {
blob_gas_used: Some(0x00),
excess_blob_gas: Some(0x00),
parent_beacon_block_root: Some(H256::zero()),
requests_hash: Some(*EMPTY_KECCACK_HASH),
requests_hash: Some(*EMPTY_KECCAK_HASH),
..Default::default()
};

Expand Down
4 changes: 2 additions & 2 deletions crates/storage/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -855,10 +855,10 @@ impl Store {
/// Checks cache first, falls back to database. If metadata is missing,
/// falls back to loading full code and extracts length (auto-migration).
pub fn get_code_metadata(&self, code_hash: H256) -> Result<Option<CodeMetadata>, StoreError> {
use ethrex_common::constants::EMPTY_KECCACK_HASH;
use ethrex_common::constants::EMPTY_KECCAK_HASH;

// Empty code special case
if code_hash == *EMPTY_KECCACK_HASH {
if code_hash == *EMPTY_KECCAK_HASH {
return Ok(Some(CodeMetadata { length: 0 }));
}

Expand Down
4 changes: 2 additions & 2 deletions crates/vm/backends/levm/db.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use ethrex_common::U256 as CoreU256;
use ethrex_common::constants::EMPTY_KECCACK_HASH;
use ethrex_common::constants::EMPTY_KECCAK_HASH;
use ethrex_common::types::{AccountState, Code, CodeMetadata};
use ethrex_common::{Address as CoreAddress, H256 as CoreH256};
use ethrex_levm::db::Database as LevmDatabase;
Expand Down Expand Up @@ -69,7 +69,7 @@ impl LevmDatabase for DatabaseLogger {
}

fn get_account_code(&self, code_hash: CoreH256) -> Result<Code, DatabaseError> {
if code_hash != *EMPTY_KECCACK_HASH {
if code_hash != *EMPTY_KECCAK_HASH {
let mut code_accessed = self
.code_accessed
.lock()
Expand Down
24 changes: 12 additions & 12 deletions crates/vm/backends/levm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use bytes::Bytes;
#[cfg(all(feature = "rayon", not(feature = "eip-8025")))]
use ethrex_common::H256;
#[cfg(all(feature = "rayon", not(feature = "eip-8025")))]
use ethrex_common::constants::EMPTY_KECCACK_HASH;
use ethrex_common::constants::EMPTY_KECCAK_HASH;
#[cfg(all(feature = "rayon", not(feature = "eip-8025")))]
use ethrex_common::types::Code;
#[cfg(all(feature = "rayon", not(feature = "eip-8025")))]
Expand Down Expand Up @@ -843,10 +843,10 @@ impl LEVM {
}

// Detect account removal (EIP-161): post-state empty but pre-state existed
let post_empty = balance.is_zero() && nonce == 0 && code_hash == *EMPTY_KECCACK_HASH;
let post_empty = balance.is_zero() && nonce == 0 && code_hash == *EMPTY_KECCAK_HASH;
let pre_empty = prestate.balance.is_zero()
&& prestate.nonce == 0
&& prestate.code_hash == *EMPTY_KECCACK_HASH;
&& prestate.code_hash == *EMPTY_KECCAK_HASH;
let removed = post_empty && !pre_empty;

let balance_changed = acct_changes
Expand Down Expand Up @@ -1654,7 +1654,7 @@ impl LEVM {
let seeded_hash = if seeded_pos > 0 {
let seeded_code = &acct.code_changes[seeded_pos - 1].new_code;
if seeded_code.is_empty() {
*EMPTY_KECCACK_HASH
*EMPTY_KECCAK_HASH
} else {
ethrex_common::utils::keccak(seeded_code)
}
Expand All @@ -1667,7 +1667,7 @@ impl LEVM {
store
.get_account_state(*addr)
.map(|a| a.code_hash)
.unwrap_or(*EMPTY_KECCACK_HASH)
.unwrap_or(*EMPTY_KECCAK_HASH)
})
};
if account.info.code_hash != seeded_hash {
Expand Down Expand Up @@ -1782,7 +1782,7 @@ impl LEVM {
if let Some(expected_code) = find_exact_change_code(&acct.code_changes, withdrawal_idx)
{
let code_hash = if expected_code.is_empty() {
*EMPTY_KECCACK_HASH
*EMPTY_KECCAK_HASH
} else {
ethrex_common::utils::keccak(expected_code)
};
Expand Down Expand Up @@ -1932,7 +1932,7 @@ impl LEVM {
// Code
if !has_exact_change_code(&acct.code_changes, withdrawal_idx) {
let seeded_hash = match acct.code_changes.last() {
Some(c) if c.new_code.is_empty() => *EMPTY_KECCACK_HASH,
Some(c) if c.new_code.is_empty() => *EMPTY_KECCAK_HASH,
Some(c) => ethrex_common::utils::keccak(&c.new_code),
None => {
db.store
Expand Down Expand Up @@ -2146,7 +2146,7 @@ impl LEVM {
store
.get_account_state(ac.address)
.ok()
.filter(|s| s.code_hash != *EMPTY_KECCACK_HASH)
.filter(|s| s.code_hash != *EMPTY_KECCAK_HASH)
.map(|s| s.code_hash)
})
.collect();
Expand Down Expand Up @@ -2934,7 +2934,7 @@ mod bal_tests {
AccountState {
balance: U256::from(100),
nonce: 5,
code_hash: *EMPTY_KECCACK_HASH,
code_hash: *EMPTY_KECCAK_HASH,
storage_root: H256::zero(),
},
);
Expand All @@ -2961,7 +2961,7 @@ mod bal_tests {
// Last balance entry wins
assert_eq!(info.balance, U256::from(80));
assert_eq!(info.nonce, 6);
assert_eq!(info.code_hash, *EMPTY_KECCACK_HASH);
assert_eq!(info.code_hash, *EMPTY_KECCAK_HASH);
// Storage
let key = ethrex_common::utils::u256_to_h256(U256::from(42));
assert_eq!(*u.added_storage.get(&key).unwrap(), U256::from(999));
Expand All @@ -2976,7 +2976,7 @@ mod bal_tests {
AccountState {
balance: U256::from(1000),
nonce: 0,
code_hash: *EMPTY_KECCACK_HASH,
code_hash: *EMPTY_KECCAK_HASH,
storage_root: H256::zero(),
},
);
Expand Down Expand Up @@ -3017,7 +3017,7 @@ mod bal_tests {
AccountState {
balance: U256::from(50),
nonce: 1,
code_hash: *EMPTY_KECCACK_HASH,
code_hash: *EMPTY_KECCAK_HASH,
storage_root: H256::zero(),
},
);
Expand Down
Loading
Loading