Skip to content

Commit 05c0508

Browse files
authored
fix(l2): fixes and cleanup of to_execution_db() (#2482)
**Motivation** Prover's execution was failing because of wrong data in the ExecutionDB. There were also some cases where data was missing but the current tests didn't catch it. **Description** - fixes saving final storage values instead of initial ones. - fixes saving only touched storage values, instead of read ones too. - removes unused `new_store` - simplifies code
1 parent d637bb2 commit 05c0508

File tree

2 files changed

+71
-126
lines changed

2 files changed

+71
-126
lines changed

crates/vm/backends/levm/db.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ use std::sync::{Arc, Mutex};
1313
#[derive(Clone)]
1414
pub struct DatabaseLogger {
1515
pub block_hashes_accessed: Arc<Mutex<HashMap<u64, CoreH256>>>,
16-
pub accounts_accessed: Arc<Mutex<Vec<CoreAddress>>>,
17-
pub storage_accessed: Arc<Mutex<HashMap<(CoreAddress, CoreH256), CoreU256>>>,
16+
pub state_accessed: Arc<Mutex<HashMap<CoreAddress, Vec<CoreH256>>>>,
1817
pub code_accessed: Arc<Mutex<Vec<CoreH256>>>,
1918
pub store: Arc<dyn LevmDatabase>,
2019
}
@@ -23,8 +22,7 @@ impl DatabaseLogger {
2322
pub fn new(store: Arc<dyn LevmDatabase>) -> Self {
2423
Self {
2524
block_hashes_accessed: Arc::new(Mutex::new(HashMap::new())),
26-
accounts_accessed: Arc::new(Mutex::new(Vec::new())),
27-
storage_accessed: Arc::new(Mutex::new(HashMap::new())),
25+
state_accessed: Arc::new(Mutex::new(HashMap::new())),
2826
code_accessed: Arc::new(Mutex::new(vec![])),
2927
store,
3028
}
@@ -36,12 +34,12 @@ impl LevmDatabase for DatabaseLogger {
3634
&self,
3735
address: CoreAddress,
3836
) -> Result<ethrex_levm::AccountInfo, DatabaseError> {
39-
let acc_info = self.store.get_account_info(address)?;
40-
self.accounts_accessed
37+
self.state_accessed
4138
.lock()
4239
.map_err(|_| DatabaseError::Custom("Could not lock mutex".to_string()))?
43-
.push(address);
44-
Ok(acc_info)
40+
.entry(address)
41+
.or_default();
42+
self.store.get_account_info(address)
4543
}
4644

4745
fn account_exists(&self, address: CoreAddress) -> bool {
@@ -53,12 +51,13 @@ impl LevmDatabase for DatabaseLogger {
5351
address: CoreAddress,
5452
key: CoreH256,
5553
) -> Result<CoreU256, DatabaseError> {
56-
let slot = self.store.get_storage_slot(address, key)?;
57-
self.storage_accessed
54+
self.state_accessed
5855
.lock()
5956
.map_err(|_| DatabaseError::Custom("Could not lock mutex".to_string()))?
60-
.insert((address, key), slot);
61-
Ok(slot)
57+
.entry(address)
58+
.and_modify(|keys| keys.push(key))
59+
.or_insert(vec![key]);
60+
self.store.get_storage_slot(address, key)
6261
}
6362

6463
fn get_block_hash(&self, block_number: u64) -> Result<Option<CoreH256>, DatabaseError> {

crates/vm/backends/levm/mod.rs

Lines changed: 60 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -404,119 +404,74 @@ impl LEVM {
404404
.map_err(Box::new)?
405405
.account_updates;
406406

407-
// index read and touched account addresses and storage keys
408-
let account_accessed = logger_ref
409-
.accounts_accessed
407+
// index accessed account addresses and storage keys
408+
let state_accessed = logger_ref
409+
.state_accessed
410410
.lock()
411411
.map_err(|_| {
412412
ExecutionDBError::Store(StoreError::Custom("Could not lock mutex".to_string()))
413413
})?
414414
.clone();
415415

416-
let mut index = Vec::with_capacity(account_accessed.len());
417-
for address in account_accessed.iter() {
418-
let storage_keys = logger_ref
419-
.storage_accessed
420-
.lock()
421-
.map_err(|_| {
422-
ExecutionDBError::Store(StoreError::Custom("Could not lock mutex".to_string()))
423-
})?
424-
.iter()
425-
.filter_map(
426-
|((addr, key), _)| {
427-
if *addr == *address {
428-
Some(key)
429-
} else {
430-
None
431-
}
432-
},
433-
)
434-
.map(|key| H256::from_slice(&key.to_fixed_bytes()))
435-
.collect::<Vec<_>>();
436-
index.push((address, storage_keys));
437-
}
416+
// fetch all read/written accounts from store
417+
let accounts = state_accessed
418+
.keys()
419+
.chain(execution_updates.iter().map(|update| &update.address))
420+
.filter_map(|address| {
421+
store
422+
.get_account_info_by_hash(parent_hash, *address)
423+
.transpose()
424+
.map(|account| Ok((*address, account?)))
425+
})
426+
.collect::<Result<HashMap<_, _>, ExecutionDBError>>()?;
438427

439-
// fetch all read/written values from store
440-
let cache_accounts = account_accessed.iter().filter_map(|address| {
441-
// filter new accounts (accounts that didn't exist before) assuming our store is
442-
// correct (based on the success of the pre-execution).
443-
if let Ok(Some(info)) = db.store.get_account_info_by_hash(parent_hash, *address) {
444-
Some((address, info))
428+
// fetch all read/written code from store
429+
let code_accessed = logger_ref
430+
.code_accessed
431+
.lock()
432+
.map_err(|_| {
433+
ExecutionDBError::Store(StoreError::Custom("Could not lock mutex".to_string()))
434+
})?
435+
.clone();
436+
let code = accounts
437+
.values()
438+
.map(|account| account.code_hash)
439+
.chain(code_accessed.into_iter())
440+
.filter_map(|hash| {
441+
store
442+
.get_account_code(hash)
443+
.transpose()
444+
.map(|account| Ok((hash, account?)))
445+
})
446+
.collect::<Result<HashMap<_, _>, ExecutionDBError>>()?;
447+
448+
// fetch all read/written storage from store
449+
let added_storage = execution_updates.iter().filter_map(|update| {
450+
if !update.added_storage.is_empty() {
451+
let keys = update.added_storage.keys().cloned().collect::<Vec<_>>();
452+
Some((update.address, keys))
445453
} else {
446454
None
447455
}
448456
});
449-
let accounts = cache_accounts
457+
let storage = state_accessed
450458
.clone()
451-
.map(|(address, _)| {
452-
// return error if account is missing
453-
let account = match db.store.get_account_info_by_hash(parent_hash, *address) {
454-
Ok(Some(some)) => Ok(some),
455-
Err(err) => Err(ExecutionDBError::Database(err)),
456-
Ok(None) => unreachable!(), // we are filtering out accounts that are not present
457-
// in the store
458-
};
459-
Ok((*address, account?))
459+
.into_iter()
460+
.chain(added_storage)
461+
.map(|(address, keys)| {
462+
let keys: Result<HashMap<_, _>, ExecutionDBError> = keys
463+
.iter()
464+
.filter_map(|key| {
465+
store
466+
.get_storage_at_hash(parent_hash, address, *key)
467+
.transpose()
468+
.map(|value| Ok((*key, value?)))
469+
})
470+
.collect();
471+
Ok((address, keys?))
460472
})
461473
.collect::<Result<HashMap<_, _>, ExecutionDBError>>()?;
462-
let mut code: HashMap<H256, Bytes> = execution_updates
463-
.clone()
464-
.iter()
465-
.map(|update| {
466-
// return error if code is missing
467-
let hash = update.info.clone().unwrap_or_default().code_hash;
468-
Ok((
469-
hash,
470-
db.store
471-
.get_account_code(hash)?
472-
.ok_or(ExecutionDBError::NewMissingCode(hash))?,
473-
))
474-
})
475-
.collect::<Result<_, ExecutionDBError>>()?;
476-
477-
let mut code_accessed = HashMap::new();
478-
479-
{
480-
let all_code_accessed = logger_ref.code_accessed.lock().map_err(|_| {
481-
ExecutionDBError::Store(StoreError::Custom("Could not lock mutex".to_string()))
482-
})?;
483-
for code_hash in all_code_accessed.iter() {
484-
code_accessed.insert(
485-
*code_hash,
486-
store
487-
.get_account_code(*code_hash)?
488-
.ok_or(ExecutionDBError::CodeNotFound(code_hash.0.into()))?
489-
.clone(),
490-
);
491-
}
492-
code.extend(code_accessed);
493-
}
494474

495-
let storage = execution_updates
496-
.iter()
497-
.map(|update| {
498-
// return error if storage is missing
499-
Ok((
500-
update.address,
501-
update
502-
.added_storage
503-
.keys()
504-
.map(|key| {
505-
let key = H256::from(key.to_fixed_bytes());
506-
let value = store
507-
.get_storage_at_hash(
508-
block.header.compute_block_hash(),
509-
update.address,
510-
key,
511-
)
512-
.map_err(ExecutionDBError::Store)?
513-
.ok_or(ExecutionDBError::NewMissingStorage(update.address, key))?;
514-
Ok((key, value))
515-
})
516-
.collect::<Result<HashMap<_, _>, ExecutionDBError>>()?,
517-
))
518-
})
519-
.collect::<Result<HashMap<_, _>, ExecutionDBError>>()?;
520475
let block_hashes = logger_ref
521476
.block_hashes_accessed
522477
.lock()
@@ -528,23 +483,14 @@ impl LEVM {
528483
.map(|(num, hash)| (num, H256::from(hash.0)))
529484
.collect();
530485

531-
let new_store = store.clone();
532-
new_store
533-
.apply_account_updates(block.hash(), &execution_updates)
534-
.await?;
535-
536486
// get account proofs
537-
let state_trie = new_store
487+
let state_trie = store
538488
.state_trie(block.hash())?
539489
.ok_or(ExecutionDBError::NewMissingStateTrie(parent_hash))?;
540490
let parent_state_trie = store
541491
.state_trie(parent_hash)?
542492
.ok_or(ExecutionDBError::NewMissingStateTrie(parent_hash))?;
543-
let hashed_addresses: Vec<_> = index
544-
.clone()
545-
.into_iter()
546-
.map(|(address, _)| hash_address(address))
547-
.collect();
493+
let hashed_addresses: Vec<_> = state_accessed.keys().map(hash_address).collect();
548494
let initial_state_proofs = parent_state_trie.get_proofs(&hashed_addresses)?;
549495
let final_state_proofs: Vec<_> = hashed_addresses
550496
.iter()
@@ -563,14 +509,14 @@ impl LEVM {
563509
// get storage proofs
564510
let mut storage_proofs = HashMap::new();
565511
let mut final_storage_proofs = HashMap::new();
566-
for (address, storage_keys) in index {
567-
let Some(parent_storage_trie) = store.storage_trie(parent_hash, *address)? else {
512+
for (address, storage_keys) in state_accessed {
513+
let Some(parent_storage_trie) = store.storage_trie(parent_hash, address)? else {
568514
// the storage of this account was empty or the account is newly created, either
569515
// way the storage trie was initially empty so there aren't any proofs to add.
570516
continue;
571517
};
572-
let storage_trie = new_store.storage_trie(block.hash(), *address)?.ok_or(
573-
ExecutionDBError::NewMissingStorageTrie(block.hash(), *address),
518+
let storage_trie = store.storage_trie(block.hash(), address)?.ok_or(
519+
ExecutionDBError::NewMissingStorageTrie(block.hash(), address),
574520
)?;
575521
let paths = storage_keys.iter().map(hash_key).collect::<Vec<_>>();
576522

@@ -594,7 +540,7 @@ impl LEVM {
594540
[initial_proofs.1, potential_child_nodes].concat(),
595541
);
596542

597-
storage_proofs.insert(*address, proofs);
543+
storage_proofs.insert(address, proofs);
598544
final_storage_proofs.insert(address, final_proofs);
599545
}
600546

0 commit comments

Comments
 (0)