1pub mod db;
2pub mod error;
3pub mod logger;
4mod nibbles;
5pub mod node;
6mod node_hash;
7pub mod rkyv_utils;
8mod rlp;
9#[cfg(test)]
10mod test_utils;
11pub mod threadpool;
12mod trie_iter;
13pub mod trie_sorted;
14mod verify_range;
15use ethereum_types::H256;
16use ethrex_crypto::keccak::keccak_hash;
17use ethrex_crypto::{Crypto, NativeCrypto};
18use ethrex_rlp::constants::RLP_NULL;
19use ethrex_rlp::encode::RLPEncode;
20use rustc_hash::{FxHashMap, FxHashSet};
21use std::collections::BTreeMap;
22use std::sync::{Arc, Mutex};
23
24pub use self::db::{InMemoryTrieDB, TrieDB};
25pub use self::logger::{TrieLogger, TrieWitness};
26pub use self::nibbles::Nibbles;
27pub use self::threadpool::ThreadPool;
28pub use self::verify_range::verify_range;
29pub use self::{
30 node::{Node, NodeRef, OnceLock},
31 node_hash::NodeHash,
32};
33
34pub use self::error::{ExtensionNodeErrorData, InconsistentTreeError, TrieError};
35use self::{node::LeafNode, trie_iter::TrieIterator};
36
37use ethrex_rlp::decode::RLPDecode;
38use lazy_static::lazy_static;
39
40lazy_static! {
41 pub static ref EMPTY_TRIE_HASH: H256 = H256(
43 keccak_hash([RLP_NULL]),
44 );
45}
46
47pub type PathRLP = Vec<u8>;
49pub type ValueRLP = Vec<u8>;
51pub type NodeRLP = Vec<u8>;
53pub type TrieNode = (Nibbles, NodeRLP);
55
56pub struct Trie {
58 db: Box<dyn TrieDB>,
59 pub root: NodeRef,
60 pending_removal: FxHashSet<Nibbles>,
61 dirty: FxHashSet<Nibbles>,
62}
63
64impl Default for Trie {
65 fn default() -> Self {
66 Self::new_temp()
67 }
68}
69
70impl Trie {
71 pub fn new(db: Box<dyn TrieDB>) -> Self {
73 Self {
74 db,
75 root: NodeRef::default(),
76 pending_removal: Default::default(),
77 dirty: Default::default(),
78 }
79 }
80
81 pub fn open(db: Box<dyn TrieDB>, root: H256) -> Self {
83 Self {
84 db,
85 root: if root != *EMPTY_TRIE_HASH {
86 NodeHash::from(root).into()
87 } else {
88 Default::default()
89 },
90 pending_removal: Default::default(),
91 dirty: Default::default(),
92 }
93 }
94
95 pub fn db(&self) -> &dyn TrieDB {
100 self.db.as_ref()
101 }
102
103 pub fn get(&self, pathrlp: &[u8]) -> Result<Option<ValueRLP>, TrieError> {
105 let path = Nibbles::from_bytes(pathrlp);
106
107 if !self.dirty.contains(&path) && self.db().flatkeyvalue_computed(path.clone()) {
108 let Some(value_rlp) = self.db.get(path)? else {
109 return Ok(None);
110 };
111 if value_rlp.is_empty() {
112 return Ok(None);
113 }
114 return Ok(Some(value_rlp));
115 }
116
117 Ok(match self.root {
118 NodeRef::Node(ref node, _) => node.get(self.db.as_ref(), path)?,
119 NodeRef::Hash(hash) if hash.is_valid() => {
120 Node::decode(&self.db.get(Nibbles::default())?.ok_or_else(|| {
121 TrieError::InconsistentTree(Box::new(InconsistentTreeError::RootNotFound(
122 hash.finalize(&NativeCrypto),
123 )))
124 })?)
125 .map_err(TrieError::RLPDecode)?
126 .get(self.db.as_ref(), path)?
127 }
128 _ => None,
129 })
130 }
131
132 pub fn insert(&mut self, path: PathRLP, value: ValueRLP) -> Result<(), TrieError> {
134 let path = Nibbles::from_bytes(&path);
135 self.pending_removal.remove(&path);
136 self.dirty.insert(path.clone());
137
138 if self.root.is_valid() {
139 self.root
141 .get_node_mut(self.db.as_ref(), Nibbles::default())?
142 .ok_or_else(|| {
143 TrieError::InconsistentTree(Box::new(InconsistentTreeError::RootNotFoundNoHash))
144 })?
145 .insert(self.db.as_ref(), path, value)?
146 } else {
147 self.root = Node::from(LeafNode::new(path, value)).into()
149 };
150 self.root.clear_hash();
151
152 Ok(())
153 }
154
155 pub fn remove(&mut self, path: &[u8]) -> Result<Option<ValueRLP>, TrieError> {
158 self.dirty.insert(Nibbles::from_bytes(path));
159 if !self.root.is_valid() {
160 return Ok(None);
161 }
162 self.pending_removal.insert(Nibbles::from_bytes(path));
163
164 let (is_trie_empty, value) = self
166 .root
167 .get_node_mut(self.db.as_ref(), Nibbles::default())?
168 .ok_or_else(|| {
169 TrieError::InconsistentTree(Box::new(InconsistentTreeError::RootNotFoundNoHash))
170 })?
171 .remove(self.db.as_ref(), Nibbles::from_bytes(path))?;
172 if is_trie_empty {
173 self.root = NodeRef::default();
174 } else {
175 self.root.clear_hash();
176 }
177
178 Ok(value)
179 }
180
181 pub fn hash(&mut self, crypto: &dyn Crypto) -> Result<H256, TrieError> {
185 self.commit(crypto)?;
186 Ok(self.hash_no_commit(crypto))
187 }
188
189 pub fn hash_no_commit(&self, crypto: &dyn Crypto) -> H256 {
192 if self.root.is_valid() {
193 let mut buf = Vec::with_capacity(512);
195 self.root
196 .compute_hash_no_alloc(&mut buf, crypto)
197 .finalize(crypto)
198 } else {
199 *EMPTY_TRIE_HASH
200 }
201 }
202
203 pub fn get_root_node(&self, path: Nibbles) -> Result<Arc<Node>, TrieError> {
204 self.root
205 .get_node_checked(self.db.as_ref(), path)?
206 .ok_or_else(|| {
207 TrieError::InconsistentTree(Box::new(InconsistentTreeError::RootNotFound(
208 self.root
209 .compute_hash(&NativeCrypto)
210 .finalize(&NativeCrypto),
211 )))
212 })
213 }
214
215 pub fn collect_changes_since_last_hash(
221 &mut self,
222 crypto: &dyn Crypto,
223 ) -> (H256, Vec<TrieNode>) {
224 let updates = self.commit_without_storing(crypto);
225 let ret_hash = self.hash_no_commit(crypto);
226 (ret_hash, updates)
227 }
228
229 pub fn commit(&mut self, crypto: &dyn Crypto) -> Result<(), TrieError> {
234 let acc = self.commit_without_storing(crypto);
235 self.db.put_batch(acc)?;
236
237 self.db.commit()?;
239
240 Ok(())
241 }
242
243 pub fn commit_without_storing(&mut self, crypto: &dyn Crypto) -> Vec<TrieNode> {
246 let mut acc = Vec::new();
247 if self.root.is_valid() {
248 self.root.commit(Nibbles::default(), &mut acc, crypto);
249 }
250 if self.root.compute_hash(crypto) == NodeHash::Hashed(*EMPTY_TRIE_HASH) {
251 acc.push((Nibbles::default(), vec![RLP_NULL]))
252 }
253 acc.extend(self.pending_removal.drain().map(|nib| (nib, vec![])));
254
255 acc
256 }
257
258 pub fn get_proof(&self, path: &[u8]) -> Result<Vec<NodeRLP>, TrieError> {
266 if self.root.is_valid() {
267 let hash = self.root.compute_hash(&NativeCrypto);
268
269 let mut node_path = Vec::new();
270 if let NodeHash::Inline((data, len)) = hash {
271 node_path.push(data[..len as usize].to_vec());
272 }
273
274 let root = match self
275 .root
276 .get_node_checked(self.db.as_ref(), Nibbles::default())?
277 {
278 Some(x) => x,
279 None => return Ok(Vec::new()),
280 };
281 root.get_path(self.db.as_ref(), Nibbles::from_bytes(path), &mut node_path)?;
282
283 Ok(node_path)
284 } else {
285 Ok(Vec::new())
286 }
287 }
288
289 pub fn get_proofs(
293 &self,
294 paths: &[PathRLP],
295 ) -> Result<(Option<NodeRLP>, Vec<NodeRLP>), TrieError> {
296 if self.root.is_valid() {
297 let encoded_root = self.get_root_node(Nibbles::default())?.encode_to_vec();
298
299 let mut node_path: FxHashSet<_> = Default::default();
300 for path in paths {
301 let mut nodes = self.get_proof(path)?;
302 nodes.swap_remove(0);
303 node_path.extend(nodes);
304 }
305
306 Ok((Some(encoded_root), node_path.into_iter().collect()))
307 } else {
308 Ok((None, Vec::new()))
309 }
310 }
311
312 pub fn empty_in_memory() -> Self {
313 Self::new(Box::new(InMemoryTrieDB::new(Arc::new(Mutex::new(
314 BTreeMap::new(),
315 )))))
316 }
317
318 pub fn get_embedded_root(
320 all_nodes: &BTreeMap<H256, Node>,
321 root_hash: H256,
322 ) -> Result<NodeRef, TrieError> {
323 if root_hash == *EMPTY_TRIE_HASH {
325 return Ok(NodeRef::default());
326 }
327
328 let root_rlp = all_nodes.get(&root_hash).ok_or_else(|| {
329 TrieError::InconsistentTree(Box::new(InconsistentTreeError::RootNotFound(root_hash)))
330 })?;
331
332 fn get_embedded_node(
333 all_nodes: &BTreeMap<H256, Node>,
334 cur_node: &Node,
335 ) -> Result<Node, TrieError> {
336 Ok(match cur_node.clone() {
337 Node::Branch(mut node) => {
338 for choice in &mut node.choices {
339 let NodeRef::Hash(hash) = *choice else {
340 continue;
341 };
342
343 if hash.is_valid() {
344 *choice = match all_nodes.get(&hash.finalize(&NativeCrypto)) {
345 Some(node) => get_embedded_node(all_nodes, node)?.into(),
346 None => hash.into(),
347 };
348 }
349 }
350
351 (*node).into()
352 }
353 Node::Extension(mut node) => {
354 let NodeRef::Hash(hash) = node.child else {
355 return Ok(node.into());
356 };
357
358 node.child = match all_nodes.get(&hash.finalize(&NativeCrypto)) {
359 Some(node) => get_embedded_node(all_nodes, node)?.into(),
360 None => hash.into(),
361 };
362
363 node.into()
364 }
365 Node::Leaf(node) => node.into(),
366 })
367 }
368
369 let root = get_embedded_node(all_nodes, root_rlp)?;
370 Ok(root.into())
371 }
372
373 pub fn get_embedded_root_committed(
377 all_nodes: &FxHashMap<H256, Node>,
378 root_hash: H256,
379 crypto: &dyn Crypto,
380 ) -> Result<NodeRef, TrieError> {
381 if root_hash == *EMPTY_TRIE_HASH {
383 return Ok(NodeRef::default());
384 }
385
386 let root_rlp = all_nodes.get(&root_hash).ok_or_else(|| {
387 TrieError::InconsistentTree(Box::new(InconsistentTreeError::RootNotFound(root_hash)))
388 })?;
389
390 fn node_with_hash(node: Node, hash: NodeHash) -> NodeRef {
397 NodeRef::Node(Arc::new(node), OnceLock::from(hash))
398 }
399
400 fn get_embedded_node_committed(
401 all_nodes: &FxHashMap<H256, Node>,
402 cur_node: &Node,
403 crypto: &dyn Crypto,
404 ) -> Result<Node, TrieError> {
405 Ok(match cur_node.clone() {
406 Node::Branch(mut node) => {
407 for choice in &mut node.choices {
408 let NodeRef::Hash(hash) = *choice else {
409 continue;
410 };
411
412 if hash.is_valid() {
413 *choice = match all_nodes.get(&hash.finalize(crypto)) {
414 Some(node) => node_with_hash(
415 get_embedded_node_committed(all_nodes, node, crypto)?,
416 hash,
417 ),
418 None => hash.into(),
419 };
420 }
421 }
422
423 (*node).into()
424 }
425 Node::Extension(mut node) => {
426 let NodeRef::Hash(hash) = node.child else {
427 return Ok(node.into());
428 };
429
430 node.child = match all_nodes.get(&hash.finalize(crypto)) {
431 Some(node) => node_with_hash(
432 get_embedded_node_committed(all_nodes, node, crypto)?,
433 hash,
434 ),
435 None => hash.into(),
436 };
437
438 node.into()
439 }
440 Node::Leaf(node) => node.into(),
441 })
442 }
443
444 let root = get_embedded_node_committed(all_nodes, root_rlp, crypto)?;
445 Ok(node_with_hash(root, NodeHash::Hashed(root_hash)))
446 }
447
448 pub fn from_nodes(
456 root_hash: H256,
457 state_nodes: &BTreeMap<H256, Node>,
458 ) -> Result<Self, TrieError> {
459 let mut trie = Trie::new(Box::new(InMemoryTrieDB::default()));
460 let root = Self::get_embedded_root(state_nodes, root_hash)?;
461 trie.root = root;
462
463 Ok(trie)
464 }
465
466 pub fn compute_hash_from_unsorted_iter(
468 iter: impl Iterator<Item = (PathRLP, ValueRLP)>,
469 crypto: &dyn Crypto,
470 ) -> H256 {
471 let mut trie = Trie::stateless();
472 for (path, value) in iter {
473 trie.insert(path, value).unwrap();
475 }
476
477 trie.hash_no_commit(crypto)
478 }
479
480 pub(crate) fn stateless() -> Trie {
483 struct NullTrieDB;
485
486 impl TrieDB for NullTrieDB {
487 fn get(&self, _key: Nibbles) -> Result<Option<Vec<u8>>, TrieError> {
488 Ok(None)
489 }
490
491 fn put_batch(&self, _key_values: Vec<TrieNode>) -> Result<(), TrieError> {
492 Ok(())
493 }
494 }
495
496 Trie::new(Box::new(NullTrieDB))
497 }
498
499 pub fn get_node(&self, partial_path: &PathRLP) -> Result<Vec<u8>, TrieError> {
502 let partial_path = match partial_path.len() {
504 n if n < 32 => Nibbles::decode_compact(partial_path),
506 32 => Nibbles::from_bytes(partial_path),
508 _ => return Ok(vec![]),
510 };
511
512 fn get_node_inner(
513 db: &dyn TrieDB,
514 current_path: Nibbles,
515 node: &Node,
516 mut partial_path: Nibbles,
517 ) -> Result<Vec<u8>, TrieError> {
518 if partial_path.is_empty() {
520 return Ok(node.encode_to_vec());
521 }
522 match node {
523 Node::Branch(branch_node) => match partial_path.next_choice() {
524 Some(idx) => {
525 let child_ref = &branch_node.choices[idx];
526 if child_ref.is_valid() {
527 let child_path = current_path.append_new(idx as u8);
528 let child_node = child_ref
529 .get_node_checked(db, child_path.clone())?
530 .ok_or_else(|| {
531 TrieError::InconsistentTree(Box::new(
532 InconsistentTreeError::NodeNotFoundOnBranchNode(
533 child_ref
534 .compute_hash(&NativeCrypto)
535 .finalize(&NativeCrypto),
536 branch_node
537 .compute_hash(&NativeCrypto)
538 .finalize(&NativeCrypto),
539 child_path.clone(),
540 ),
541 ))
542 })?;
543 get_node_inner(db, child_path, &child_node, partial_path)
544 } else {
545 Ok(vec![])
546 }
547 }
548 _ => Ok(vec![]),
549 },
550 Node::Extension(extension_node) => {
551 if partial_path.skip_prefix(&extension_node.prefix)
552 && extension_node.child.is_valid()
553 {
554 let child_path = partial_path.concat(&extension_node.prefix);
555 let child_node = extension_node
556 .child
557 .get_node_checked(db, child_path.clone())?
558 .ok_or_else(|| {
559 TrieError::InconsistentTree(Box::new(
560 InconsistentTreeError::ExtensionNodeChildNotFound(
561 ExtensionNodeErrorData {
562 node_hash: extension_node
563 .child
564 .compute_hash(&NativeCrypto)
565 .finalize(&NativeCrypto),
566 extension_node_hash: extension_node
567 .compute_hash(&NativeCrypto)
568 .finalize(&NativeCrypto),
569 extension_node_prefix: extension_node.prefix.clone(),
570 node_path: child_path.clone(),
571 },
572 ),
573 ))
574 })?;
575 get_node_inner(db, child_path, &child_node, partial_path)
576 } else {
577 Ok(vec![])
578 }
579 }
580 Node::Leaf(_) => Ok(vec![]),
581 }
582 }
583
584 if self.root.is_valid() {
586 let root_node = self.get_root_node(Default::default())?;
587 get_node_inner(
588 self.db.as_ref(),
589 Default::default(),
590 &root_node,
591 partial_path,
592 )
593 } else {
594 Ok(Vec::new())
595 }
596 }
597
598 pub fn root_node(&self) -> Result<Option<Arc<Node>>, TrieError> {
599 if self.root.is_valid() {
600 self.root.get_node(self.db.as_ref(), Nibbles::default())
601 } else {
602 Ok(None)
603 }
604 }
605
606 pub fn new_temp() -> Self {
608 let db = InMemoryTrieDB::new(Default::default());
609 Trie::new(Box::new(db))
610 }
611
612 pub fn new_temp_with_root(root: NodeRef) -> Self {
616 let db = InMemoryTrieDB::new(Default::default());
617 let mut trie = Trie::new(Box::new(db));
618 trie.root = root;
619 trie
620 }
621
622 pub fn validate(self) -> Result<(), TrieError> {
629 let mut expected_count = if self.root.is_valid() { 1 } else { 0 };
630 for (_, node) in self.into_iter() {
631 expected_count -= 1;
632 match node {
633 Node::Branch(branch_node) => {
634 expected_count += branch_node
635 .choices
636 .iter()
637 .filter(|child| child.is_valid())
638 .count();
639 }
640 Node::Extension(_) => {
641 expected_count += 1;
642 }
643 Node::Leaf(_) => {}
644 }
645 }
646 if expected_count != 0 {
647 return Err(TrieError::Verify(format!(
648 "Node count mismatch, expected {expected_count} more"
649 )));
650 }
651 Ok(())
652 }
653
654 pub fn validate_parallel(self) -> Result<(), TrieError> {
657 use rayon::prelude::*;
658
659 if !self.root.is_valid() {
660 return Ok(());
661 }
662
663 let db = &*self.db;
664 let root_node = self
665 .root
666 .get_node_checked(db, Nibbles::default())?
667 .ok_or_else(|| TrieError::Verify("Root node not found".to_string()))?;
668
669 match &*root_node {
670 Node::Branch(branch_node) => {
671 let children: Vec<(Nibbles, NodeRef)> = branch_node
672 .choices
673 .iter()
674 .enumerate()
675 .filter(|(_, child)| child.is_valid())
676 .map(|(i, child)| {
677 let path = Nibbles::default().append_new(i as u8);
678 (path, child.clone())
679 })
680 .collect();
681
682 children.par_iter().try_for_each(|(start_path, start_ref)| {
683 validate_subtree(db, start_path.clone(), start_ref.clone())
684 })
685 }
686 _ => {
687 validate_subtree(db, Nibbles::default(), self.root.clone())
689 }
690 }
691 }
692}
693
694fn validate_subtree(
697 db: &dyn TrieDB,
698 start_path: Nibbles,
699 start_ref: NodeRef,
700) -> Result<(), TrieError> {
701 let mut expected_count: isize = 1;
702 let mut stack = vec![(start_path, start_ref)];
703
704 while let Some((path, node_ref)) = stack.pop() {
705 let node = node_ref
706 .get_node_checked(db, path.clone())?
707 .ok_or_else(|| TrieError::Verify(format!("Missing node at path {path:?}")))?;
708
709 expected_count -= 1;
710 match &*node {
711 Node::Branch(branch) => {
712 for (choice, child) in branch.choices.iter().enumerate().rev() {
713 if child.is_valid() {
714 expected_count += 1;
715 stack.push((path.append_new(choice as u8), child.clone()));
716 }
717 }
718 }
719 Node::Extension(ext) => {
720 expected_count += 1;
721 stack.push((path.concat(&ext.prefix), ext.child.clone()));
722 }
723 Node::Leaf(_) => {}
724 }
725 }
726
727 if expected_count != 0 {
728 return Err(TrieError::Verify(format!(
729 "Node count mismatch in subtree, expected {expected_count} more"
730 )));
731 }
732 Ok(())
733}
734
735impl IntoIterator for Trie {
736 type Item = (Nibbles, Node);
737
738 type IntoIter = TrieIterator;
739
740 fn into_iter(self) -> Self::IntoIter {
741 TrieIterator::new(self)
742 }
743}
744
745pub struct ProofTrie(Trie);
746
747impl ProofTrie {
748 pub fn insert(
749 &mut self,
750 partial_path: Nibbles,
751 external_ref: NodeHash,
752 ) -> Result<(), TrieError> {
753 if self.0.root.is_valid() {
754 self.0
756 .root
757 .get_node_mut(self.0.db.as_ref(), Nibbles::default())?
758 .ok_or_else(|| {
759 TrieError::InconsistentTree(Box::new(InconsistentTreeError::RootNotFoundNoHash))
760 })?
761 .insert(self.0.db.as_ref(), partial_path, external_ref)?;
762 self.0.root.clear_hash();
763 } else {
764 self.0.root = external_ref.into();
765 };
766
767 Ok(())
768 }
769
770 pub fn hash(&self, crypto: &dyn Crypto) -> H256 {
771 self.0.hash_no_commit(crypto)
772 }
773}
774
775impl From<Trie> for ProofTrie {
776 fn from(value: Trie) -> Self {
777 Self(value)
778 }
779}