Skip to content

Commit 96e6433

Browse files
edg-lOppenjrchatruc
authored
perf(l1, l2): move post-execution trie updates to the background (#4989)
**Motivation** This PR moves the trie portion of the `apply_updates` function to a background thread, improving block execution times. This background thread receives messages through a channel to apply new trie updates and does two things: - First, it updates the in-memory diff layers and notifies the process that sent the message (i.e. the block production thread) so it can continue with block execution. - Second, it performs the logic of persisting the bottom-most diff layer to disk. To do this, we first pause the ongoing thread in charge of generating the snapshots (i.e. FlatKeyValue) through a message, then persist the diff layer to disk, then notify again the thread to continue snapshot generation. **Description** <!-- A clear and concise general description of the changes this PR introduces --> <!-- Link to issues: Resolves #111, Resolves #222 --> Closes #issue_number --------- Co-authored-by: Mario Rugiero <[email protected]> Co-authored-by: Javier Chatruc <[email protected]> Co-authored-by: Javier Rodríguez Chatruc <[email protected]>
1 parent ebb341b commit 96e6433

File tree

6 files changed

+278
-168
lines changed

6 files changed

+278
-168
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77
- Reusing FindNode message per lookup loop instead of randomizing the key for each message. [#5047](https://github.com/lambdaclass/ethrex/pull/5047)
88

9+
### 2025-10-23
10+
11+
- Move trie updates post block execution to a background thread. [#4989](https://github.com/lambdaclass/ethrex/pull/4989).
12+
913
### 2025-10-21
1014

1115
- Instead of lazy computation of blocklist, do greedy computation of allowlist and store the result, fetch it with the DB. [#4961](https://github.com/lambdaclass/ethrex/pull/4961)

crates/networking/p2p/snap.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ mod tests {
180180
use ethrex_common::{BigEndianHash, H256, types::AccountState};
181181
use ethrex_rlp::{decode::RLPDecode, encode::RLPEncode};
182182
use ethrex_storage::EngineType;
183+
use ethrex_trie::EMPTY_TRIE_HASH;
183184

184185
use crate::rlpx::snap::AccountStateSlim;
185186

@@ -996,7 +997,7 @@ mod tests {
996997

997998
// Create a store and load it up with the accounts
998999
let store = Store::new("null", EngineType::InMemory).unwrap();
999-
let mut state_trie = store.new_state_trie_for_test()?;
1000+
let mut state_trie = store.open_direct_state_trie(*EMPTY_TRIE_HASH)?;
10001001
for (address, account) in accounts {
10011002
let hashed_address = H256::from_str(address).unwrap().as_bytes().to_vec();
10021003
let account = AccountState::from(AccountStateSlim::decode(&account).unwrap());

crates/storage/store.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,7 +1538,7 @@ mod tests {
15381538
})
15391539
.collect();
15401540
accounts.sort_by_key(|a| a.0);
1541-
let mut trie = store.open_state_trie(*EMPTY_TRIE_HASH).unwrap();
1541+
let mut trie = store.open_direct_state_trie(*EMPTY_TRIE_HASH).unwrap();
15421542
for (address, state) in &accounts {
15431543
trie.insert(address.0.to_vec(), state.encode_to_vec())
15441544
.unwrap();
@@ -1564,13 +1564,13 @@ mod tests {
15641564
.collect();
15651565
slots.sort_by_key(|a| a.0);
15661566
let mut trie = store
1567-
.open_storage_trie(address, *EMPTY_TRIE_HASH, *EMPTY_TRIE_HASH)
1567+
.open_direct_storage_trie(address, *EMPTY_TRIE_HASH)
15681568
.unwrap();
15691569
for (slot, value) in &slots {
15701570
trie.insert(slot.0.to_vec(), value.encode_to_vec()).unwrap();
15711571
}
15721572
let storage_root = trie.hash().unwrap();
1573-
let mut trie = store.open_state_trie(*EMPTY_TRIE_HASH).unwrap();
1573+
let mut trie = store.open_direct_state_trie(*EMPTY_TRIE_HASH).unwrap();
15741574
trie.insert(
15751575
address.0.to_vec(),
15761576
AccountState {

crates/storage/store_db/in_memory.rs

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use std::{
1515
collections::HashMap,
1616
fmt::Debug,
1717
path::Path,
18-
sync::{Arc, Mutex, MutexGuard, RwLock},
18+
sync::{Arc, Mutex, MutexGuard},
1919
};
2020

2121
// NOTE: we use a different commit threshold than rocksdb since tests
@@ -39,7 +39,7 @@ pub struct StoreInner {
3939
// Maps transaction hashes to their blocks (height+hash) and index within the blocks.
4040
transaction_locations: HashMap<H256, Vec<(BlockNumber, BlockHash, Index)>>,
4141
receipts: HashMap<BlockHash, HashMap<Index, Receipt>>,
42-
trie_cache: Arc<RwLock<TrieLayerCache>>,
42+
trie_cache: Arc<TrieLayerCache>,
4343
// Contains account trie nodes
4444
state_trie_nodes: NodeMap,
4545
pending_blocks: HashMap<BlockHash, Block>,
@@ -91,31 +91,28 @@ impl StoreEngine for Store {
9191
let mut store = self.inner()?;
9292

9393
// Store trie updates
94-
{
95-
let mut trie = store
96-
.trie_cache
97-
.write()
98-
.map_err(|_| StoreError::LockError)?;
99-
let parent = update_batch
100-
.blocks
101-
.first()
102-
.ok_or(StoreError::UpdateBatchNoBlocks)?
103-
.header
104-
.parent_hash;
105-
106-
let pre_state_root = store
107-
.headers
108-
.get(&parent)
109-
.map(|header| header.state_root)
110-
.unwrap_or_default();
111-
112-
let last_state_root = update_batch
113-
.blocks
114-
.last()
115-
.ok_or(StoreError::UpdateBatchNoBlocks)?
116-
.header
117-
.state_root;
94+
let mut trie = TrieLayerCache::clone(&store.trie_cache);
95+
let parent = update_batch
96+
.blocks
97+
.first()
98+
.ok_or(StoreError::UpdateBatchNoBlocks)?
99+
.header
100+
.parent_hash;
101+
102+
let pre_state_root = store
103+
.headers
104+
.get(&parent)
105+
.map(|header| header.state_root)
106+
.unwrap_or_default();
107+
108+
let last_state_root = update_batch
109+
.blocks
110+
.last()
111+
.ok_or(StoreError::UpdateBatchNoBlocks)?
112+
.header
113+
.state_root;
118114

115+
{
119116
let mut state_trie = store
120117
.state_trie_nodes
121118
.lock()
@@ -131,19 +128,21 @@ impl StoreEngine for Store {
131128
}
132129
}
133130
}
134-
let key_values = update_batch
135-
.storage_updates
136-
.into_iter()
137-
.flat_map(|(account_hash, nodes)| {
138-
nodes
139-
.into_iter()
140-
.map(move |(path, node)| (apply_prefix(Some(account_hash), path), node))
141-
})
142-
.chain(update_batch.account_updates)
143-
.collect();
144-
trie.put_batch(pre_state_root, last_state_root, key_values);
145131
}
146132

133+
let key_values = update_batch
134+
.storage_updates
135+
.into_iter()
136+
.flat_map(|(account_hash, nodes)| {
137+
nodes
138+
.into_iter()
139+
.map(move |(path, node)| (apply_prefix(Some(account_hash), path), node))
140+
})
141+
.chain(update_batch.account_updates)
142+
.collect();
143+
trie.put_batch(pre_state_root, last_state_root, key_values);
144+
store.trie_cache = Arc::new(trie);
145+
147146
for block in update_batch.blocks {
148147
// store block
149148
let number = block.header.number;

0 commit comments

Comments
 (0)