1use crate::rstd::{boxed::Box, convert::TryInto, marker::PhantomData, vec, vec::Vec};
18
19use hash_db::{HashDBRef, Hasher};
20
21use crate::{
22 nibble::LeftNibbleSlice,
23 nibble_ops::NIBBLE_LENGTH,
24 node::{NodeHandle, NodeHandlePlan, NodePlan, OwnedNode, Value, ValuePlan},
25 recorder::Record,
26 CError, ChildReference, DBValue, NibbleSlice, NodeCodec, Recorder, Result as TrieResult, Trie,
27 TrieDBBuilder, TrieError, TrieHash, TrieLayout,
28};
29
30struct StackEntry<'a, C: NodeCodec> {
31 prefix: LeftNibbleSlice<'a>,
33 node: OwnedNode<Vec<u8>>,
35 node_hash: Option<C::HashOut>,
37 omit_value: bool,
39 child_index: usize,
42 children: Vec<Option<ChildReference<C::HashOut>>>,
44 output_index: Option<usize>,
46 _marker: PhantomData<C>,
47}
48
49impl<'a, C: NodeCodec> StackEntry<'a, C> {
50 fn new(
51 prefix: LeftNibbleSlice<'a>,
52 node_data: Vec<u8>,
53 node_hash: Option<C::HashOut>,
54 output_index: Option<usize>,
55 ) -> TrieResult<Self, C::HashOut, C::Error> {
56 let node = OwnedNode::new::<C>(node_data)
57 .map_err(|err| Box::new(TrieError::DecoderError(node_hash.unwrap_or_default(), err)))?;
58 let children_len = match node.node_plan() {
59 NodePlan::Empty | NodePlan::Leaf { .. } => 0,
60 NodePlan::Extension { .. } => 1,
61 NodePlan::Branch { .. } | NodePlan::NibbledBranch { .. } => NIBBLE_LENGTH,
62 };
63 Ok(StackEntry {
64 prefix,
65 node,
66 node_hash,
67 omit_value: false,
68 child_index: 0,
69 children: vec![None; children_len],
70 output_index,
71 _marker: PhantomData::default(),
72 })
73 }
74
75 fn encode_node(mut self) -> TrieResult<Vec<u8>, C::HashOut, C::Error> {
77 let omit_value = self.omit_value;
78 let node_data = self.node.data();
79 let value_with_omission = |value_range: ValuePlan| -> Option<Value> {
80 if !omit_value {
81 Some(value_range.build(&node_data))
82 } else {
83 None
84 }
85 };
86 let encoded = match self.node.node_plan() {
87 NodePlan::Empty => node_data.to_vec(),
88 NodePlan::Leaf { .. } if !omit_value => node_data.to_vec(),
89 NodePlan::Leaf { partial, value: _ } => {
90 let partial = partial.build(node_data);
91 C::leaf_node(partial.right_iter(), partial.len(), Value::Inline(&[]))
92 },
93 NodePlan::Extension { .. } if self.child_index == 0 => node_data.to_vec(),
94 NodePlan::Extension { partial: partial_plan, child: _ } => {
95 let partial = partial_plan.build(node_data);
96 let child = self.children[0].expect(
97 "for extension nodes, children[0] is guaranteed to be Some when \
98 child_index > 0; \
99 the branch guard guarantees that child_index > 0",
100 );
101 C::extension_node(partial.right_iter(), partial.len(), child)
102 },
103 NodePlan::Branch { value, children } => {
104 Self::complete_branch_children(
105 node_data,
106 children,
107 self.child_index,
108 &mut self.children,
109 )?;
110 C::branch_node(
111 self.children.into_iter(),
112 value.clone().map(value_with_omission).flatten(),
113 )
114 },
115 NodePlan::NibbledBranch { partial: partial_plan, value, children } => {
116 let partial = partial_plan.build(node_data);
117 Self::complete_branch_children(
118 node_data,
119 children,
120 self.child_index,
121 &mut self.children,
122 )?;
123 C::branch_node_nibbled(
124 partial.right_iter(),
125 partial.len(),
126 self.children.into_iter(),
127 value.clone().map(value_with_omission).flatten(),
128 )
129 },
130 };
131 Ok(encoded)
132 }
133
134 fn complete_branch_children(
140 node_data: &[u8],
141 child_handles: &[Option<NodeHandlePlan>; NIBBLE_LENGTH],
142 child_index: usize,
143 children: &mut [Option<ChildReference<C::HashOut>>],
144 ) -> TrieResult<(), C::HashOut, C::Error> {
145 for i in child_index..NIBBLE_LENGTH {
146 children[i] = child_handles[i]
147 .as_ref()
148 .map(|child_plan| {
149 child_plan.build(node_data).try_into().map_err(|hash| {
150 Box::new(TrieError::InvalidHash(C::HashOut::default(), hash))
151 })
152 })
153 .transpose()?;
154 }
155 Ok(())
156 }
157
158 fn set_child(&mut self, encoded_child: &[u8]) {
162 let child_ref = match self.node.node_plan() {
163 NodePlan::Empty | NodePlan::Leaf { .. } => panic!(
164 "empty and leaf nodes have no children; \
165 thus they are never descended into; \
166 thus set_child will not be called on an entry with one of these types"
167 ),
168 NodePlan::Extension { child, .. } => {
169 assert_eq!(
170 self.child_index, 0,
171 "extension nodes only have one child; \
172 set_child is called when the only child is popped from the stack; \
173 child_index is 0 before child is pushed to the stack; qed"
174 );
175 Some(Self::replacement_child_ref(encoded_child, child))
176 },
177 NodePlan::Branch { children, .. } | NodePlan::NibbledBranch { children, .. } => {
178 assert!(
179 self.child_index < NIBBLE_LENGTH,
180 "extension nodes have at most NIBBLE_LENGTH children; \
181 set_child is called when the only child is popped from the stack; \
182 child_index is <NIBBLE_LENGTH before child is pushed to the stack; qed"
183 );
184 children[self.child_index]
185 .as_ref()
186 .map(|child| Self::replacement_child_ref(encoded_child, child))
187 },
188 };
189 self.children[self.child_index] = child_ref;
190 self.child_index += 1;
191 }
192
193 fn replacement_child_ref(
197 encoded_child: &[u8],
198 child: &NodeHandlePlan,
199 ) -> ChildReference<C::HashOut> {
200 match child {
201 NodeHandlePlan::Hash(_) => ChildReference::Inline(C::HashOut::default(), 0),
202 NodeHandlePlan::Inline(_) => {
203 let mut hash = C::HashOut::default();
204 assert!(
205 encoded_child.len() <= hash.as_ref().len(),
206 "the encoding of the raw inline node is checked to be at most the hash length
207 before descending; \
208 the encoding of the proof node is always smaller than the raw node as data is \
209 only stripped"
210 );
211 hash.as_mut()[..encoded_child.len()].copy_from_slice(encoded_child);
212 ChildReference::Inline(hash, encoded_child.len())
213 },
214 }
215 }
216}
217
218pub fn generate_proof<'a, D, L, I, K>(
222 db: &D,
223 root: &TrieHash<L>,
224 keys: I,
225) -> TrieResult<Vec<Vec<u8>>, TrieHash<L>, CError<L>>
226where
227 D: HashDBRef<L::Hash, DBValue>,
228 L: TrieLayout,
229 I: IntoIterator<Item = &'a K>,
230 K: 'a + AsRef<[u8]>,
231{
232 let mut keys = keys.into_iter().map(|key| key.as_ref()).collect::<Vec<_>>();
234 keys.sort();
235 keys.dedup();
236
237 let mut stack = <Vec<StackEntry<L::Codec>>>::new();
240
241 let mut proof_nodes = Vec::new();
243
244 for key_bytes in keys {
245 let key = LeftNibbleSlice::new(key_bytes);
246
247 unwind_stack(&mut stack, &mut proof_nodes, Some(&key))?;
249
250 let mut recorder = Recorder::<L>::new();
252 let expected_value = {
253 let trie = TrieDBBuilder::<L>::new(db, root).with_recorder(&mut recorder).build();
254 trie.get(key_bytes)?
255 };
256
257 let mut recorded_nodes = recorder.drain().into_iter().peekable();
258
259 {
263 let mut stack_iter = stack.iter().peekable();
264 while let (Some(next_record), Some(next_entry)) =
265 (recorded_nodes.peek(), stack_iter.peek())
266 {
267 if next_entry.node_hash != Some(next_record.hash) {
268 break
269 }
270 recorded_nodes.next();
271 stack_iter.next();
272 }
273 }
274
275 loop {
276 let step = match stack.last_mut() {
277 Some(entry) => match_key_to_node::<L::Codec>(
278 entry.node.data(),
279 entry.node.node_plan(),
280 &mut entry.omit_value,
281 &mut entry.child_index,
282 &mut entry.children,
283 &key,
284 entry.prefix.len(),
285 &mut recorded_nodes,
286 )?,
287 None =>
289 Step::Descend { child_prefix_len: 0, child: NodeHandle::Hash(root.as_ref()) },
290 };
291
292 match step {
293 Step::Descend { child_prefix_len, child } => {
294 let child_prefix = key.truncate(child_prefix_len);
295 let child_entry = match child {
296 NodeHandle::Hash(hash) => {
297 let child_record = recorded_nodes.next().expect(
298 "this function's trie traversal logic mirrors that of Lookup; \
299 thus the sequence of traversed nodes must be the same; \
300 so the next child node must have been recorded and must have \
301 the expected hash",
302 );
303 assert_eq!(child_record.hash.as_ref(), hash);
305
306 let output_index = proof_nodes.len();
307 proof_nodes.push(Vec::new());
310 StackEntry::new(
311 child_prefix,
312 child_record.data,
313 Some(child_record.hash),
314 Some(output_index),
315 )?
316 },
317 NodeHandle::Inline(data) => {
318 if data.len() > L::Hash::LENGTH {
319 return Err(Box::new(TrieError::InvalidHash(
320 <TrieHash<L>>::default(),
321 data.to_vec(),
322 )))
323 }
324 StackEntry::new(child_prefix, data.to_vec(), None, None)?
325 },
326 };
327 stack.push(child_entry);
328 },
329 Step::FoundHashedValue(value) => {
330 assert_eq!(
331 Some(&value),
332 expected_value.as_ref(),
333 "expected_value is found using `trie_db::Lookup`; \
334 value is found by traversing the same nodes recorded during the lookup \
335 using the same logic; \
336 thus the values found must be equal"
337 );
338 assert!(
339 recorded_nodes.next().is_none(),
340 "the recorded nodes are only recorded on the lookup path to the current \
341 key; \
342 recorded nodes is the minimal sequence of trie nodes on the lookup path; \
343 the value was found by traversing recorded nodes, so there must be none \
344 remaining"
345 );
346 break
347 },
348 Step::FoundValue(value) => {
349 assert_eq!(
350 value,
351 expected_value.as_ref().map(|v| v.as_ref()),
352 "expected_value is found using `trie_db::Lookup`; \
353 value is found by traversing the same nodes recorded during the lookup \
354 using the same logic; \
355 thus the values found must be equal"
356 );
357 assert!(
358 recorded_nodes.next().is_none(),
359 "the recorded nodes are only recorded on the lookup path to the current \
360 key; \
361 recorded nodes is the minimal sequence of trie nodes on the lookup path; \
362 the value was found by traversing recorded nodes, so there must be none \
363 remaining"
364 );
365 break
366 },
367 }
368 }
369 }
370
371 unwind_stack::<L::Codec>(&mut stack, &mut proof_nodes, None)?;
372 Ok(proof_nodes)
373}
374
375enum Step<'a> {
376 Descend { child_prefix_len: usize, child: NodeHandle<'a> },
377 FoundValue(Option<&'a [u8]>),
378 FoundHashedValue(Vec<u8>),
379}
380
381fn resolve_value<C: NodeCodec>(
382 recorded_nodes: &mut dyn Iterator<Item = Record<C::HashOut>>,
383) -> TrieResult<Step<'static>, C::HashOut, C::Error> {
384 if let Some(resolve_value) = recorded_nodes.next() {
385 Ok(Step::FoundHashedValue(resolve_value.data))
386 } else {
387 Err(Box::new(TrieError::IncompleteDatabase(C::HashOut::default())))
388 }
389}
390
391fn match_key_to_node<'a, C: NodeCodec>(
394 node_data: &'a [u8],
395 node_plan: &NodePlan,
396 omit_value: &mut bool,
397 child_index: &mut usize,
398 children: &mut [Option<ChildReference<C::HashOut>>],
399 key: &LeftNibbleSlice,
400 prefix_len: usize,
401 recorded_nodes: &mut dyn Iterator<Item = Record<C::HashOut>>,
402) -> TrieResult<Step<'a>, C::HashOut, C::Error> {
403 Ok(match node_plan {
404 NodePlan::Empty => Step::FoundValue(None),
405 NodePlan::Leaf { partial: partial_plan, value: value_range } => {
406 let partial = partial_plan.build(node_data);
407 if key.contains(&partial, prefix_len) && key.len() == prefix_len + partial.len() {
408 match value_range {
409 ValuePlan::Inline(value_range) => {
410 *omit_value = true;
411 Step::FoundValue(Some(&node_data[value_range.clone()]))
412 },
413 ValuePlan::Node(..) => {
414 *omit_value = true;
415 resolve_value::<C>(recorded_nodes)?
416 },
417 }
418 } else {
419 Step::FoundValue(None)
420 }
421 },
422 NodePlan::Extension { partial: partial_plan, child: child_plan } => {
423 let partial = partial_plan.build(node_data);
424 if key.contains(&partial, prefix_len) {
425 assert_eq!(*child_index, 0);
426 let child_prefix_len = prefix_len + partial.len();
427 let child = child_plan.build(&node_data);
428 Step::Descend { child_prefix_len, child }
429 } else {
430 Step::FoundValue(None)
431 }
432 },
433 NodePlan::Branch { value, children: child_handles } => match_key_to_branch_node::<C>(
434 node_data,
435 value.as_ref(),
436 &child_handles,
437 omit_value,
438 child_index,
439 children,
440 key,
441 prefix_len,
442 NibbleSlice::new(&[]),
443 recorded_nodes,
444 )?,
445 NodePlan::NibbledBranch { partial: partial_plan, value, children: child_handles } =>
446 match_key_to_branch_node::<C>(
447 node_data,
448 value.as_ref(),
449 &child_handles,
450 omit_value,
451 child_index,
452 children,
453 key,
454 prefix_len,
455 partial_plan.build(node_data),
456 recorded_nodes,
457 )?,
458 })
459}
460
461fn match_key_to_branch_node<'a, 'b, C: NodeCodec>(
462 node_data: &'a [u8],
463 value_range: Option<&'b ValuePlan>,
464 child_handles: &'b [Option<NodeHandlePlan>; NIBBLE_LENGTH],
465 omit_value: &mut bool,
466 child_index: &mut usize,
467 children: &mut [Option<ChildReference<C::HashOut>>],
468 key: &'b LeftNibbleSlice<'b>,
469 prefix_len: usize,
470 partial: NibbleSlice<'b>,
471 recorded_nodes: &mut dyn Iterator<Item = Record<C::HashOut>>,
472) -> TrieResult<Step<'a>, C::HashOut, C::Error> {
473 if !key.contains(&partial, prefix_len) {
474 return Ok(Step::FoundValue(None))
475 }
476
477 if key.len() == prefix_len + partial.len() {
478 let value = match value_range {
479 Some(ValuePlan::Inline(range)) => {
480 *omit_value = true;
481 Some(&node_data[range.clone()])
482 },
483 Some(ValuePlan::Node(..)) => {
484 *omit_value = true;
485 return resolve_value::<C>(recorded_nodes)
486 },
487 None => None,
488 };
489 return Ok(Step::FoundValue(value))
490 }
491
492 let new_index = key.at(prefix_len + partial.len()).expect(
493 "key contains partial key after entry key offset; \
494 thus key len is greater than equal to entry key len plus partial key len; \
495 also they are unequal due to else condition;
496 qed",
497 ) as usize;
498 assert!(*child_index <= new_index);
499 while *child_index < new_index {
500 children[*child_index] = child_handles[*child_index]
501 .as_ref()
502 .map(|child_plan| {
503 child_plan
504 .build(node_data)
505 .try_into()
506 .map_err(|hash| Box::new(TrieError::InvalidHash(C::HashOut::default(), hash)))
507 })
508 .transpose()?;
509 *child_index += 1;
510 }
511 if let Some(child_plan) = &child_handles[*child_index] {
512 Ok(Step::Descend {
513 child_prefix_len: prefix_len + partial.len() + 1,
514 child: child_plan.build(node_data),
515 })
516 } else {
517 Ok(Step::FoundValue(None))
518 }
519}
520
521fn unwind_stack<C: NodeCodec>(
525 stack: &mut Vec<StackEntry<C>>,
526 proof_nodes: &mut Vec<Vec<u8>>,
527 maybe_key: Option<&LeftNibbleSlice>,
528) -> TrieResult<(), C::HashOut, C::Error> {
529 while let Some(entry) = stack.pop() {
530 match maybe_key {
531 Some(key) if key.starts_with(&entry.prefix) => {
532 stack.push(entry);
534 break
535 },
536 _ => {
537 let index = entry.output_index;
539 let encoded = entry.encode_node()?;
540 if let Some(parent_entry) = stack.last_mut() {
541 parent_entry.set_child(&encoded);
542 }
543 if let Some(index) = index {
544 proof_nodes[index] = encoded;
545 }
546 },
547 }
548 }
549 Ok(())
550}