1use super::{
4 BranchNodeCompact, EMPTY_ROOT_HASH, Nibbles, TrieMask,
5 nodes::{BranchNodeRef, ExtensionNodeRef, LeafNodeRef},
6 proof::ProofRetainer,
7};
8use crate::{HashMap, nodes::RlpNode, proof::ProofNodes};
9use alloc::vec::Vec;
10use alloy_primitives::{B256, keccak256};
11use alloy_rlp::EMPTY_STRING_CODE;
12use core::cmp;
13use tracing::trace;
14
15mod value;
16pub use value::{HashBuilderValue, HashBuilderValueRef};
17
18#[derive(Debug, Clone, Default)]
43#[allow(missing_docs)]
44pub struct HashBuilder {
45 pub key: Nibbles,
46 pub value: HashBuilderValue,
47 pub stack: Vec<RlpNode>,
48
49 pub state_masks: Vec<TrieMask>,
50 pub tree_masks: Vec<TrieMask>,
51 pub hash_masks: Vec<TrieMask>,
52
53 pub stored_in_database: bool,
54
55 pub updated_branch_nodes: Option<HashMap<Nibbles, BranchNodeCompact>>,
56 pub proof_retainer: Option<ProofRetainer>,
57
58 pub rlp_buf: Vec<u8>,
59}
60
61impl HashBuilder {
62 pub fn with_updates(mut self, retain_updates: bool) -> Self {
66 self.set_updates(retain_updates);
67 self
68 }
69
70 pub fn with_proof_retainer(mut self, retainer: ProofRetainer) -> Self {
72 self.proof_retainer = Some(retainer);
73 self
74 }
75
76 pub fn set_updates(&mut self, retain_updates: bool) {
80 if retain_updates {
81 self.updated_branch_nodes = Some(HashMap::default());
82 }
83 }
84
85 pub fn split(mut self) -> (Self, HashMap<Nibbles, BranchNodeCompact>) {
87 let updates = self.updated_branch_nodes.take();
88 (self, updates.unwrap_or_default())
89 }
90
91 pub fn take_proof_nodes(&mut self) -> ProofNodes {
93 self.proof_retainer.take().map(ProofRetainer::into_proof_nodes).unwrap_or_default()
94 }
95
96 pub fn updates_len(&self) -> usize {
99 self.updated_branch_nodes.as_ref().map(|u| u.len()).unwrap_or(0)
100 }
101
102 #[cfg(feature = "std")]
104 pub fn print_stack(&self) {
105 println!("============ STACK ===============");
106 for item in &self.stack {
107 println!("{}", alloy_primitives::hex::encode(item));
108 }
109 println!("============ END STACK ===============");
110 }
111
112 pub fn add_leaf(&mut self, key: Nibbles, value: &[u8]) {
118 assert!(key > self.key, "add_leaf key {:?} self.key {:?}", key, self.key);
119 self.add_leaf_unchecked(key, value);
120 }
121
122 pub fn add_leaf_unchecked(&mut self, key: Nibbles, value: &[u8]) {
127 debug_assert!(key > self.key, "add_leaf_unchecked key {:?} self.key {:?}", key, self.key);
128 if !self.key.is_empty() {
129 self.update(&key);
130 }
131 self.set_key_value(key, HashBuilderValueRef::Bytes(value));
132 }
133
134 pub fn add_branch(&mut self, key: Nibbles, value: B256, stored_in_database: bool) {
136 assert!(
137 key > self.key || (self.key.is_empty() && key.is_empty()),
138 "add_branch key {:?} self.key {:?}",
139 key,
140 self.key
141 );
142 if !self.key.is_empty() {
143 self.update(&key);
144 } else if key.is_empty() {
145 self.stack.push(RlpNode::word_rlp(&value));
146 }
147 self.set_key_value(key, HashBuilderValueRef::Hash(&value));
148 self.stored_in_database = stored_in_database;
149 }
150
151 pub fn root(&mut self) -> B256 {
153 if !self.key.is_empty() {
155 self.update(&Nibbles::default());
156 self.key.clear();
157 self.value.clear();
158 }
159 let root = self.current_root();
160 if root == EMPTY_ROOT_HASH {
161 if let Some(proof_retainer) = self.proof_retainer.as_mut() {
162 proof_retainer.retain(&Nibbles::default(), &[EMPTY_STRING_CODE])
163 }
164 }
165 root
166 }
167
168 #[inline]
169 fn set_key_value(&mut self, key: Nibbles, value: HashBuilderValueRef<'_>) {
170 self.log_key_value("old value");
171 self.key = key;
172 self.value.set_from_ref(value);
173 self.log_key_value("new value");
174 }
175
176 fn log_key_value(&self, msg: &str) {
177 trace!(target: "trie::hash_builder",
178 key = ?self.key,
179 value = ?self.value,
180 "{msg}",
181 );
182 }
183
184 fn current_root(&self) -> B256 {
185 if let Some(node_ref) = self.stack.last() {
186 if let Some(hash) = node_ref.as_hash() { hash } else { keccak256(node_ref) }
187 } else {
188 EMPTY_ROOT_HASH
189 }
190 }
191
192 fn update(&mut self, succeeding: &Nibbles) {
197 let mut build_extensions = false;
198 let mut current = self.key;
200 debug_assert!(!current.is_empty());
201
202 trace!(target: "trie::hash_builder", ?current, ?succeeding, "updating merkle tree");
203
204 let mut i = 0usize;
205 loop {
206 let _span = tracing::trace_span!(target: "trie::hash_builder", "loop", i, ?current, build_extensions).entered();
207
208 let preceding_exists = !self.state_masks.is_empty();
209 let preceding_len = self.state_masks.len().saturating_sub(1);
210
211 let common_prefix_len = succeeding.common_prefix_length(¤t);
212 let len = cmp::max(preceding_len, common_prefix_len);
213 assert!(len < current.len(), "len {} current.len {}", len, current.len());
214
215 trace!(
216 target: "trie::hash_builder",
217 ?len,
218 ?common_prefix_len,
219 ?preceding_len,
220 preceding_exists,
221 "prefix lengths after comparing keys"
222 );
223
224 let extra_digit = current.get_unchecked(len);
226 if self.state_masks.len() <= len {
227 let new_len = len + 1;
228 trace!(target: "trie::hash_builder", new_len, old_len = self.state_masks.len(), "scaling state masks to fit");
229 self.state_masks.resize(new_len, TrieMask::default());
230 }
231 self.state_masks[len] |= TrieMask::from_nibble(extra_digit);
232 trace!(
233 target: "trie::hash_builder",
234 ?extra_digit,
235 state_masks = ?self.state_masks,
236 );
237
238 if self.tree_masks.len() < current.len() {
240 self.resize_masks(current.len());
241 }
242
243 let mut len_from = len;
244 if !succeeding.is_empty() || preceding_exists {
245 len_from += 1;
246 }
247 trace!(target: "trie::hash_builder", "skipping {len_from} nibbles");
248
249 let short_node_key = current.slice(len_from..);
251 trace!(target: "trie::hash_builder", ?short_node_key);
252
253 if !build_extensions {
255 match self.value.as_ref() {
256 HashBuilderValueRef::Bytes(leaf_value) => {
257 let leaf_node = LeafNodeRef::new(&short_node_key, leaf_value);
258 self.rlp_buf.clear();
259 let rlp = leaf_node.rlp(&mut self.rlp_buf);
260
261 let path = current.slice(..len_from);
262 trace!(
263 target: "trie::hash_builder",
264 ?path,
265 ?leaf_node,
266 ?rlp,
267 "pushing leaf node",
268 );
269 self.stack.push(rlp);
270 self.retain_proof_from_buf(&path);
271 }
272 HashBuilderValueRef::Hash(hash) => {
273 trace!(target: "trie::hash_builder", ?hash, "pushing branch node hash");
274 self.stack.push(RlpNode::word_rlp(hash));
275
276 if self.stored_in_database {
277 self.tree_masks[current.len() - 1] |=
278 TrieMask::from_nibble(current.last().unwrap());
279 }
280 self.hash_masks[current.len() - 1] |=
281 TrieMask::from_nibble(current.last().unwrap());
282
283 build_extensions = true;
284 }
285 }
286 }
287
288 if build_extensions && !short_node_key.is_empty() {
289 self.update_masks(¤t, len_from);
290 let stack_last = self.stack.pop().expect("there should be at least one stack item");
291 let extension_node = ExtensionNodeRef::new(&short_node_key, &stack_last);
292
293 self.rlp_buf.clear();
294 let rlp = extension_node.rlp(&mut self.rlp_buf);
295
296 let path = current.slice(..len_from);
297 trace!(
298 target: "trie::hash_builder",
299 ?path,
300 ?extension_node,
301 ?rlp,
302 "pushing extension node",
303 );
304 self.stack.push(rlp);
305 self.retain_proof_from_buf(&path);
306 self.resize_masks(len_from);
307 }
308
309 if preceding_len <= common_prefix_len && !succeeding.is_empty() {
310 trace!(target: "trie::hash_builder", "no common prefix to create branch nodes from, returning");
311 return;
312 }
313
314 if !succeeding.is_empty() || preceding_exists {
316 let children = self.push_branch_node(¤t, len);
318 self.store_branch_node(¤t, len, children);
320 }
321
322 self.state_masks.resize(len, TrieMask::default());
323 self.resize_masks(len);
324
325 if preceding_len == 0 {
326 trace!(target: "trie::hash_builder", "0 or 1 state masks means we have no more elements to process");
327 return;
328 }
329
330 current.truncate(preceding_len);
331 trace!(target: "trie::hash_builder", ?current, "truncated nibbles to {} bytes", preceding_len);
332
333 trace!(target: "trie::hash_builder", state_masks = ?self.state_masks, "popping empty state masks");
334 while self.state_masks.last() == Some(&TrieMask::default()) {
335 self.state_masks.pop();
336 }
337
338 build_extensions = true;
339
340 i += 1;
341 }
342 }
343
344 fn push_branch_node(&mut self, current: &Nibbles, len: usize) -> Vec<B256> {
351 let state_mask = self.state_masks[len];
352 let hash_mask = self.hash_masks[len];
353 let branch_node = BranchNodeRef::new(&self.stack, state_mask);
354 let children = if self.updated_branch_nodes.is_some() {
356 branch_node.child_hashes(hash_mask).collect()
357 } else {
358 vec![]
359 };
360
361 self.rlp_buf.clear();
362 let rlp = branch_node.rlp(&mut self.rlp_buf);
363 let path = current.slice(..len);
364 trace!(
365 target: "trie::hash_builder",
366 ?path,
367 ?branch_node,
368 ?rlp,
369 "pushing branch node",
370 );
371 self.retain_proof_from_buf(&path);
372
373 let first_child_idx = self.stack.len() - state_mask.count_ones() as usize;
375 trace!(
376 target: "trie::hash_builder",
377 new_len = first_child_idx,
378 old_len = self.stack.len(),
379 "resizing stack to prepare branch node"
380 );
381 self.stack.resize_with(first_child_idx, Default::default);
382
383 self.stack.push(rlp);
384 children
385 }
386
387 fn store_branch_node(&mut self, current: &Nibbles, len: usize, children: Vec<B256>) {
392 if len > 0 {
393 let parent_index = len - 1;
394 self.hash_masks[parent_index] |=
395 TrieMask::from_nibble(current.get_unchecked(parent_index));
396 }
397
398 let store_in_db_trie = !self.tree_masks[len].is_empty() || !self.hash_masks[len].is_empty();
399 if store_in_db_trie {
400 if len > 0 {
401 let parent_index = len - 1;
402 self.tree_masks[parent_index] |=
403 TrieMask::from_nibble(current.get_unchecked(parent_index));
404 }
405
406 if self.updated_branch_nodes.is_some() {
407 let common_prefix = current.slice(..len);
408 let node = BranchNodeCompact::new(
409 self.state_masks[len],
410 self.tree_masks[len],
411 self.hash_masks[len],
412 children,
413 (len == 0).then(|| self.current_root()),
414 );
415 self.updated_branch_nodes.as_mut().unwrap().insert(common_prefix, node);
416 }
417 }
418 }
419
420 fn retain_proof_from_buf(&mut self, prefix: &Nibbles) {
421 if let Some(proof_retainer) = self.proof_retainer.as_mut() {
422 proof_retainer.retain(prefix, &self.rlp_buf)
423 }
424 }
425
426 fn update_masks(&mut self, current: &Nibbles, len_from: usize) {
427 if len_from > 0 {
428 let flag = TrieMask::from_nibble(current.get_unchecked(len_from - 1));
429
430 self.hash_masks[len_from - 1] &= !flag;
431
432 if !self.tree_masks[current.len() - 1].is_empty() {
433 self.tree_masks[len_from - 1] |= flag;
434 }
435 }
436 }
437
438 fn resize_masks(&mut self, new_len: usize) {
439 trace!(
440 target: "trie::hash_builder",
441 new_len,
442 old_tree_mask_len = self.tree_masks.len(),
443 old_hash_mask_len = self.hash_masks.len(),
444 "resizing tree/hash masks"
445 );
446 self.tree_masks.resize(new_len, TrieMask::default());
447 self.hash_masks.resize(new_len, TrieMask::default());
448 }
449}
450
451#[cfg(test)]
452mod tests {
453 use super::*;
454 use crate::{nodes::LeafNode, triehash_trie_root};
455 use alloc::collections::BTreeMap;
456 use alloy_primitives::{U256, b256, hex};
457 use alloy_rlp::Encodable;
458
459 fn assert_hashed_trie_root<'a, I, K>(iter: I)
461 where
462 I: Iterator<Item = (K, &'a U256)>,
463 K: AsRef<[u8]> + Ord,
464 {
465 let hashed = iter
466 .map(|(k, v)| (keccak256(k.as_ref()), alloy_rlp::encode(v).to_vec()))
467 .collect::<BTreeMap<_, _>>();
469
470 let mut hb = HashBuilder::default();
471
472 hashed.iter().for_each(|(key, val)| {
473 let nibbles = Nibbles::unpack(key);
474 hb.add_leaf(nibbles, val);
475 });
476
477 assert_eq!(hb.root(), triehash_trie_root(&hashed));
478 }
479
480 fn assert_trie_root<I, K, V>(iter: I)
482 where
483 I: IntoIterator<Item = (K, V)>,
484 K: AsRef<[u8]> + Ord,
485 V: AsRef<[u8]>,
486 {
487 let mut hb = HashBuilder::default();
488
489 let data = iter.into_iter().collect::<BTreeMap<_, _>>();
490 data.iter().for_each(|(key, val)| {
491 let nibbles = Nibbles::unpack(key.as_ref());
492 hb.add_leaf(nibbles, val.as_ref());
493 });
494
495 assert_eq!(hb.root(), triehash_trie_root(data));
496 }
497
498 #[test]
499 fn empty() {
500 assert_eq!(HashBuilder::default().root(), EMPTY_ROOT_HASH);
501 }
502
503 #[test]
504 #[cfg(feature = "arbitrary")]
505 #[cfg_attr(miri, ignore = "no proptest")]
506 fn arbitrary_hashed_root() {
507 use proptest::prelude::*;
508 proptest!(|(state: BTreeMap<B256, U256>)| {
509 assert_hashed_trie_root(state.iter());
510 });
511 }
512
513 #[test]
514 fn test_generates_branch_node() {
515 let mut hb = HashBuilder::default().with_updates(true);
516
517 let data = BTreeMap::from([
535 (
536 hex!("1000000000000000000000000000000000000000000000000000000000000000").to_vec(),
539 Vec::new(),
540 ),
541 (
542 hex!("1100000000000000000000000000000000000000000000000000000000000000").to_vec(),
543 Vec::new(),
544 ),
545 (
546 hex!("1110000000000000000000000000000000000000000000000000000000000000").to_vec(),
547 Vec::new(),
548 ),
549 (
550 hex!("1200000000000000000000000000000000000000000000000000000000000000").to_vec(),
551 Vec::new(),
552 ),
553 (
554 hex!("1220000000000000000000000000000000000000000000000000000000000000").to_vec(),
555 Vec::new(),
556 ),
557 (
558 hex!("1320000000000000000000000000000000000000000000000000000000000000").to_vec(),
561 Vec::new(),
562 ),
563 ]);
564 data.iter().for_each(|(key, val)| {
565 let nibbles = Nibbles::unpack(key);
566 hb.add_leaf(nibbles, val.as_ref());
567 });
568 let _root = hb.root();
569
570 let (_, updates) = hb.split();
571
572 let update = updates.get(&Nibbles::from_nibbles_unchecked(hex!("01"))).unwrap();
573 assert_eq!(update.state_mask, TrieMask::new(0b1111));
575 assert_eq!(update.tree_mask, TrieMask::new(0b0000));
577 assert_eq!(update.hash_mask, TrieMask::new(0b0110));
579 assert_eq!(update.hashes.len(), 2);
581
582 assert_eq!(_root, triehash_trie_root(data));
583 }
584
585 #[test]
586 fn test_root_raw_data() {
587 let data = [
588 (hex!("646f").to_vec(), hex!("76657262").to_vec()),
589 (hex!("676f6f64").to_vec(), hex!("7075707079").to_vec()),
590 (hex!("676f6b32").to_vec(), hex!("7075707079").to_vec()),
591 (hex!("676f6b34").to_vec(), hex!("7075707079").to_vec()),
592 ];
593 assert_trie_root(data);
594 }
595
596 #[test]
597 fn test_root_rlp_hashed_data() {
598 let data: HashMap<_, _, _> = HashMap::from([
599 (B256::with_last_byte(1), U256::from(2)),
600 (B256::with_last_byte(3), U256::from(4)),
601 ]);
602 assert_hashed_trie_root(data.iter());
603 }
604
605 #[test]
606 fn test_root_known_hash() {
607 let root_hash = b256!("45596e474b536a6b4d64764e4f75514d544577646c414e684271706871446456");
608 let mut hb = HashBuilder::default();
609 hb.add_branch(Nibbles::default(), root_hash, false);
610 assert_eq!(hb.root(), root_hash);
611 }
612
613 #[test]
614 fn manual_branch_node_ok() {
615 let raw_input = vec![
616 (hex!("646f").to_vec(), hex!("76657262").to_vec()),
617 (hex!("676f6f64").to_vec(), hex!("7075707079").to_vec()),
618 ];
619 let expected = triehash_trie_root(raw_input.clone());
620
621 let mut hb = HashBuilder::default();
623 for (key, val) in &raw_input {
624 hb.add_leaf(Nibbles::unpack(key), val);
625 }
626
627 let leaf1 = LeafNode::new(Nibbles::unpack(&raw_input[0].0[1..]), raw_input[0].1.clone());
631 let leaf2 = LeafNode::new(Nibbles::unpack(&raw_input[1].0[1..]), raw_input[1].1.clone());
632 let mut branch: [&dyn Encodable; 17] = [b""; 17];
633 branch[4] = &leaf1;
636 branch[7] = &leaf2;
637 let mut branch_node_rlp = Vec::new();
638 alloy_rlp::encode_list::<_, dyn Encodable>(&branch, &mut branch_node_rlp);
639 let branch_node_hash = keccak256(branch_node_rlp);
640
641 let mut hb2 = HashBuilder::default();
642 hb2.add_branch(Nibbles::from_nibbles_unchecked([0x6]), branch_node_hash, false);
644
645 assert_eq!(hb.root(), expected);
646 assert_eq!(hb2.root(), expected);
647 }
648}