1use crate::api::tables::{
2 ACCOUNT_FLATKEYVALUE, ACCOUNT_TRIE_NODES, STORAGE_FLATKEYVALUE, STORAGE_TRIE_NODES,
3};
4use crate::api::{StorageBackend, StorageLockedView, StorageReadView};
5use crate::error::StoreError;
6use crate::layering::apply_prefix;
7use ethrex_common::H256;
8use ethrex_trie::{Nibbles, TrieDB, error::TrieError};
9use std::sync::Arc;
10
11pub struct BackendTrieDB {
14 db: Arc<dyn StorageBackend>,
16 read_view: Arc<dyn StorageReadView>,
20 last_computed_flatkeyvalue: Nibbles,
22 nodes_table: &'static str,
23 fkv_table: &'static str,
24 address_prefix: Option<H256>,
27}
28
29impl BackendTrieDB {
30 pub fn new_for_accounts(
32 db: Arc<dyn StorageBackend>,
33 last_written: Vec<u8>,
34 ) -> Result<Self, StoreError> {
35 let read_view = db.begin_read()?;
36 Self::new_for_accounts_with_view(db, read_view, last_written)
37 }
38
39 pub fn new_for_accounts_with_view(
41 db: Arc<dyn StorageBackend>,
42 read_view: Arc<dyn StorageReadView>,
43 last_written: Vec<u8>,
44 ) -> Result<Self, StoreError> {
45 let last_computed_flatkeyvalue = Nibbles::from_hex(last_written);
46 Ok(Self {
47 db,
48 read_view,
49 last_computed_flatkeyvalue,
50 nodes_table: ACCOUNT_TRIE_NODES,
51 fkv_table: ACCOUNT_FLATKEYVALUE,
52 address_prefix: None,
53 })
54 }
55
56 pub fn new_for_storages(
58 db: Arc<dyn StorageBackend>,
59 last_written: Vec<u8>,
60 ) -> Result<Self, StoreError> {
61 let read_view = db.begin_read()?;
62 Self::new_for_storages_with_view(db, read_view, last_written)
63 }
64
65 pub fn new_for_storages_with_view(
67 db: Arc<dyn StorageBackend>,
68 read_view: Arc<dyn StorageReadView>,
69 last_written: Vec<u8>,
70 ) -> Result<Self, StoreError> {
71 let last_computed_flatkeyvalue = Nibbles::from_hex(last_written);
72 Ok(Self {
73 db,
74 read_view,
75 last_computed_flatkeyvalue,
76 nodes_table: STORAGE_TRIE_NODES,
77 fkv_table: STORAGE_FLATKEYVALUE,
78 address_prefix: None,
79 })
80 }
81
82 pub fn new_for_account_storage(
84 db: Arc<dyn StorageBackend>,
85 address_prefix: H256,
86 last_written: Vec<u8>,
87 ) -> Result<Self, StoreError> {
88 let read_view = db.begin_read()?;
89 Self::new_for_account_storage_with_view(db, read_view, address_prefix, last_written)
90 }
91
92 pub fn new_for_account_storage_with_view(
94 db: Arc<dyn StorageBackend>,
95 read_view: Arc<dyn StorageReadView>,
96 address_prefix: H256,
97 last_written: Vec<u8>,
98 ) -> Result<Self, StoreError> {
99 let last_computed_flatkeyvalue = Nibbles::from_hex(last_written);
100 Ok(Self {
101 db,
102 read_view,
103 last_computed_flatkeyvalue,
104 nodes_table: STORAGE_TRIE_NODES,
105 fkv_table: STORAGE_FLATKEYVALUE,
106 address_prefix: Some(address_prefix),
107 })
108 }
109
110 fn make_key(&self, path: Nibbles) -> Vec<u8> {
111 apply_prefix(self.address_prefix, path).into_vec()
112 }
113
114 fn table_for_key(&self, key: &[u8]) -> &'static str {
116 let (is_leaf, _) = classify_trie_key(key.len());
117 if is_leaf {
118 self.fkv_table
119 } else {
120 self.nodes_table
121 }
122 }
123}
124
125pub fn classify_trie_key(key_len: usize) -> (bool, bool) {
136 let is_leaf = key_len == 65 || key_len == 131;
137 let is_account = key_len <= 65;
138 (is_leaf, is_account)
139}
140
141impl TrieDB for BackendTrieDB {
142 fn flatkeyvalue_computed(&self, key: Nibbles) -> bool {
143 let key = apply_prefix(self.address_prefix, key);
144 self.last_computed_flatkeyvalue >= key
145 }
146
147 fn get(&self, key: Nibbles) -> Result<Option<Vec<u8>>, TrieError> {
148 let prefixed_key = self.make_key(key);
149 let table = self.table_for_key(&prefixed_key);
150 self.read_view
151 .get(table, prefixed_key.as_ref())
152 .map_err(|e| TrieError::DbError(anyhow::anyhow!("Failed to get from database: {}", e)))
153 }
154
155 fn multi_get(&self, keys: &[Nibbles]) -> Vec<Result<Option<Vec<u8>>, TrieError>> {
156 let prefixed_keys: Vec<Vec<u8>> = keys.iter().map(|k| self.make_key(k.clone())).collect();
160
161 let mut by_table: std::collections::HashMap<&'static str, Vec<(usize, &[u8])>> =
163 std::collections::HashMap::new();
164 for (idx, key) in prefixed_keys.iter().enumerate() {
165 let table = self.table_for_key(key);
166 by_table.entry(table).or_default().push((idx, key.as_ref()));
167 }
168
169 let mut results: Vec<Option<Result<Option<Vec<u8>>, TrieError>>> =
170 (0..keys.len()).map(|_| None).collect();
171
172 for (table, entries) in by_table {
173 let (indices, refs): (Vec<usize>, Vec<&[u8]>) = entries.into_iter().unzip();
174 let table_results = self.read_view.multi_get(table, &refs);
175 for (idx, res) in indices.into_iter().zip(table_results) {
176 results[idx] = Some(res.map_err(|e| {
177 TrieError::DbError(anyhow::anyhow!("Failed to get from database: {}", e))
178 }));
179 }
180 }
181
182 results
183 .into_iter()
184 .map(|r| r.expect("every key is assigned to exactly one table"))
185 .collect()
186 }
187
188 fn put_batch(&self, key_values: Vec<(Nibbles, Vec<u8>)>) -> Result<(), TrieError> {
189 let mut tx = self.db.begin_write().map_err(|e| {
190 TrieError::DbError(anyhow::anyhow!("Failed to begin write transaction: {}", e))
191 })?;
192 for (key, value) in key_values {
193 let prefixed_key = self.make_key(key);
194 let table = self.table_for_key(&prefixed_key);
195 tx.put_batch(table, vec![(prefixed_key, value)])
196 .map_err(|e| TrieError::DbError(anyhow::anyhow!("Failed to write batch: {}", e)))?;
197 }
198 tx.commit()
199 .map_err(|e| TrieError::DbError(anyhow::anyhow!("Failed to write batch: {}", e)))
200 }
201}
202
203pub struct BackendTrieDBLocked {
205 account_trie_tx: Box<dyn StorageLockedView>,
206 storage_trie_tx: Box<dyn StorageLockedView>,
207 account_fkv_tx: Box<dyn StorageLockedView>,
208 storage_fkv_tx: Box<dyn StorageLockedView>,
209 last_computed_flatkeyvalue: Nibbles,
211}
212
213impl BackendTrieDBLocked {
214 pub fn new(engine: &dyn StorageBackend, last_written: Vec<u8>) -> Result<Self, StoreError> {
215 let last_computed_flatkeyvalue = Nibbles::from_hex(last_written);
216 let account_trie_tx = engine.begin_locked(ACCOUNT_TRIE_NODES)?;
217 let storage_trie_tx = engine.begin_locked(STORAGE_TRIE_NODES)?;
218 let account_fkv_tx = engine.begin_locked(ACCOUNT_FLATKEYVALUE)?;
219 let storage_fkv_tx = engine.begin_locked(STORAGE_FLATKEYVALUE)?;
220 Ok(Self {
221 account_trie_tx,
222 storage_trie_tx,
223 account_fkv_tx,
224 storage_fkv_tx,
225 last_computed_flatkeyvalue,
226 })
227 }
228
229 fn tx_for_key(&self, key: &Nibbles) -> &dyn StorageLockedView {
231 let (is_leaf, is_account) = classify_trie_key(key.len());
232 if is_leaf {
233 if is_account {
234 &*self.account_fkv_tx
235 } else {
236 &*self.storage_fkv_tx
237 }
238 } else if is_account {
239 &*self.account_trie_tx
240 } else {
241 &*self.storage_trie_tx
242 }
243 }
244}
245
246impl TrieDB for BackendTrieDBLocked {
247 fn flatkeyvalue_computed(&self, key: Nibbles) -> bool {
248 self.last_computed_flatkeyvalue >= key
249 }
250
251 fn get(&self, key: Nibbles) -> Result<Option<Vec<u8>>, TrieError> {
252 let tx = self.tx_for_key(&key);
253 tx.get(key.as_ref())
254 .map_err(|e| TrieError::DbError(anyhow::anyhow!("Failed to get from database: {}", e)))
255 }
256
257 fn put_batch(&self, _key_values: Vec<(Nibbles, Vec<u8>)>) -> Result<(), TrieError> {
258 Err(TrieError::DbError(anyhow::anyhow!("trie is read-only")))
260 }
261}