1use crate::{
18 nibble::LeftNibbleSlice,
19 nibble_ops::NIBBLE_LENGTH,
20 node::{Node, NodeHandle, Value},
21 rstd::{convert::TryInto, iter::Peekable, marker::PhantomData, result::Result, vec, vec::Vec},
22 CError, ChildReference, NodeCodec, TrieHash, TrieLayout,
23};
24use hash_db::Hasher;
25
26#[derive(PartialEq, Eq)]
30#[cfg_attr(feature = "std", derive(Debug))]
31pub enum Error<HO, CE> {
32 DuplicateKey(Vec<u8>),
35 ExtraneousNode,
37 ExtraneousValue(Vec<u8>),
40 ExtraneousHashReference(HO),
42 InvalidChildReference(Vec<u8>),
44 ValueMismatch(Vec<u8>),
46 IncompleteProof,
48 RootMismatch(HO),
50 DecodeError(CE),
52}
53
54#[cfg(feature = "std")]
55impl<HO: std::fmt::Debug, CE: std::error::Error> std::fmt::Display for Error<HO, CE> {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
57 match self {
58 Error::DuplicateKey(key) =>
59 write!(f, "Duplicate key in input statement: key={:?}", key),
60 Error::ExtraneousNode => write!(f, "Extraneous node found in proof"),
61 Error::ExtraneousValue(key) =>
62 write!(f, "Extraneous value found in proof should have been omitted: key={:?}", key),
63 Error::ExtraneousHashReference(hash) => write!(
64 f,
65 "Extraneous hash reference found in proof should have been omitted: hash={:?}",
66 hash
67 ),
68 Error::InvalidChildReference(data) =>
69 write!(f, "Invalid child reference exceeds hash length: {:?}", data),
70 Error::ValueMismatch(key) =>
71 write!(f, "Expected value was not found in the trie: key={:?}", key),
72 Error::IncompleteProof => write!(f, "Proof is incomplete -- expected more nodes"),
73 Error::RootMismatch(hash) => write!(f, "Computed incorrect root {:?} from proof", hash),
74 Error::DecodeError(err) => write!(f, "Unable to decode proof node: {}", err),
75 }
76 }
77}
78
79#[cfg(feature = "std")]
80impl<HO: std::fmt::Debug, CE: std::error::Error + 'static> std::error::Error for Error<HO, CE> {
81 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
82 match self {
83 Error::DecodeError(err) => Some(err),
84 _ => None,
85 }
86 }
87}
88
89struct StackEntry<'a, L: TrieLayout> {
90 prefix: LeftNibbleSlice<'a>,
92 node: Node<'a>,
93 is_inline: bool,
94 value: Option<Value<'a>>,
96 child_index: usize,
99 children: Vec<Option<ChildReference<TrieHash<L>>>>,
101 next_value_hash: Option<TrieHash<L>>,
103 _marker: PhantomData<L>,
104}
105
106impl<'a, L: TrieLayout> StackEntry<'a, L> {
107 fn new(
108 node_data: &'a [u8],
109 prefix: LeftNibbleSlice<'a>,
110 is_inline: bool,
111 ) -> Result<Self, Error<TrieHash<L>, CError<L>>> {
112 let node = L::Codec::decode(&node_data[..]).map_err(Error::DecodeError)?;
113 let children_len = match &node {
114 Node::Empty | Node::Leaf(..) => 0,
115 Node::Extension(..) => 1,
116 Node::Branch(..) | Node::NibbledBranch(..) => NIBBLE_LENGTH,
117 };
118 let value = match &node {
119 Node::Empty | Node::Extension(_, _) => None,
120 Node::Leaf(_, value) => Some(value.clone()),
121 Node::Branch(_, value) | Node::NibbledBranch(_, _, value) => value.clone(),
122 };
123 Ok(StackEntry {
124 node,
125 is_inline,
126 prefix,
127 value,
128 child_index: 0,
129 children: vec![None; children_len],
130 next_value_hash: None,
131 _marker: PhantomData::default(),
132 })
133 }
134
135 fn value(&self) -> Option<Value> {
136 if let Some(hash) = self.next_value_hash.as_ref() {
137 Some(Value::Node(hash.as_ref()))
138 } else {
139 self.value.clone()
140 }
141 }
142
143 fn encode_node(mut self) -> Result<Vec<u8>, Error<TrieHash<L>, CError<L>>> {
145 self.complete_children()?;
146 Ok(match self.node {
147 Node::Empty => L::Codec::empty_node().to_vec(),
148 Node::Leaf(partial, _) => {
149 let value = self.value().expect(
150 "value is assigned to Some in StackEntry::new; \
151 value is only ever reassigned in the ValueMatch::MatchesLeaf match \
152 clause, which assigns only to Some",
153 );
154 L::Codec::leaf_node(partial.right_iter(), partial.len(), value)
155 },
156 Node::Extension(partial, _) => {
157 let child =
158 self.children[0].expect("the child must be completed since child_index is 1");
159 L::Codec::extension_node(partial.right_iter(), partial.len(), child)
160 },
161 Node::Branch(_, _) => L::Codec::branch_node(self.children.iter(), self.value()),
162 Node::NibbledBranch(partial, _, _) => L::Codec::branch_node_nibbled(
163 partial.right_iter(),
164 partial.len(),
165 self.children.iter(),
166 self.value(),
167 ),
168 })
169 }
170
171 fn advance_child_index<I>(
172 &mut self,
173 child_prefix: LeftNibbleSlice<'a>,
174 proof_iter: &mut I,
175 ) -> Result<Self, Error<TrieHash<L>, CError<L>>>
176 where
177 I: Iterator<Item = &'a [u8]>,
178 {
179 match self.node {
180 Node::Extension(_, child) => {
181 assert_eq!(self.child_index, 0);
183 Self::make_child_entry(proof_iter, child, child_prefix)
184 },
185 Node::Branch(children, _) | Node::NibbledBranch(_, children, _) => {
186 assert!(child_prefix.len() > 0);
188 let child_index = child_prefix
189 .at(child_prefix.len() - 1)
190 .expect("it's less than prefix.len(); qed") as usize;
191 while self.child_index < child_index {
192 if let Some(child) = children[self.child_index] {
193 let child_ref = child.try_into().map_err(Error::InvalidChildReference)?;
194 self.children[self.child_index] = Some(child_ref);
195 }
196 self.child_index += 1;
197 }
198 let child = children[self.child_index].expect("guaranteed by advance_item");
199 Self::make_child_entry(proof_iter, child, child_prefix)
200 },
201 _ => panic!("cannot have children"),
202 }
203 }
204
205 fn complete_children(&mut self) -> Result<(), Error<TrieHash<L>, CError<L>>> {
207 match self.node {
208 Node::Extension(_, child) if self.child_index == 0 => {
209 let child_ref = child.try_into().map_err(Error::InvalidChildReference)?;
210 self.children[self.child_index] = Some(child_ref);
211 self.child_index += 1;
212 },
213 Node::Branch(children, _) | Node::NibbledBranch(_, children, _) => {
214 while self.child_index < NIBBLE_LENGTH {
215 if let Some(child) = children[self.child_index] {
216 let child_ref = child.try_into().map_err(Error::InvalidChildReference)?;
217 self.children[self.child_index] = Some(child_ref);
218 }
219 self.child_index += 1;
220 }
221 },
222 _ => {},
223 }
224 Ok(())
225 }
226
227 fn make_child_entry<I>(
228 proof_iter: &mut I,
229 child: NodeHandle<'a>,
230 prefix: LeftNibbleSlice<'a>,
231 ) -> Result<Self, Error<TrieHash<L>, CError<L>>>
232 where
233 I: Iterator<Item = &'a [u8]>,
234 {
235 match child {
236 NodeHandle::Inline(data) =>
237 if data.is_empty() {
238 let node_data = proof_iter.next().ok_or(Error::IncompleteProof)?;
239 StackEntry::new(node_data, prefix, false)
240 } else {
241 StackEntry::new(data, prefix, true)
242 },
243 NodeHandle::Hash(data) => {
244 let mut hash = TrieHash::<L>::default();
245 if data.len() != hash.as_ref().len() {
246 return Err(Error::InvalidChildReference(data.to_vec()))
247 }
248 hash.as_mut().copy_from_slice(data);
249 Err(Error::ExtraneousHashReference(hash))
250 },
251 }
252 }
253
254 fn set_value(&mut self, value: &'a [u8]) {
255 self.value = if L::MAX_INLINE_VALUE.map_or(true, |max| max as usize > value.len()) {
256 Some(Value::Inline(value))
257 } else {
258 let hash = L::Hash::hash(value);
259 self.next_value_hash = Some(hash);
260 None
262 };
263 }
264
265 fn advance_item<I>(
266 &mut self,
267 items_iter: &mut Peekable<I>,
268 ) -> Result<Step<'a>, Error<TrieHash<L>, CError<L>>>
269 where
270 I: Iterator<Item = (&'a [u8], Option<&'a [u8]>)>,
271 {
272 let step = loop {
273 if let Some((key_bytes, value)) = items_iter.peek().cloned() {
274 let key = LeftNibbleSlice::new(key_bytes);
275 if key.starts_with(&self.prefix) {
276 match match_key_to_node(&key, self.prefix.len(), &self.node) {
277 ValueMatch::MatchesLeaf =>
278 if let Some(value) = value {
279 self.set_value(value);
280 } else {
281 return Err(Error::ValueMismatch(key_bytes.to_vec()))
282 },
283 ValueMatch::MatchesBranch =>
284 if let Some(value) = value {
285 self.set_value(value);
286 } else {
287 self.value = None;
288 },
289 ValueMatch::NotFound =>
290 if value.is_some() {
291 return Err(Error::ValueMismatch(key_bytes.to_vec()))
292 },
293 ValueMatch::NotOmitted =>
294 return Err(Error::ExtraneousValue(key_bytes.to_vec())),
295 ValueMatch::IsChild(child_prefix) => break Step::Descend(child_prefix),
296 }
297
298 items_iter.next();
299 continue
300 }
301 }
302 break Step::UnwindStack
303 };
304 Ok(step)
305 }
306}
307
308enum ValueMatch<'a> {
309 MatchesLeaf,
311 MatchesBranch,
313 NotFound,
315 NotOmitted,
317 IsChild(LeftNibbleSlice<'a>),
319}
320
321fn match_key_to_node<'a>(
324 key: &LeftNibbleSlice<'a>,
325 prefix_len: usize,
326 node: &Node,
327) -> ValueMatch<'a> {
328 match node {
329 Node::Empty => ValueMatch::NotFound,
330 Node::Leaf(partial, value) => {
331 if key.contains(partial, prefix_len) && key.len() == prefix_len + partial.len() {
332 match value {
333 Value::Node(..) => ValueMatch::NotOmitted,
334 Value::Inline(value) =>
335 if value.is_empty() {
336 ValueMatch::MatchesLeaf
337 } else {
338 ValueMatch::NotOmitted
339 },
340 }
341 } else {
342 ValueMatch::NotFound
343 }
344 },
345 Node::Extension(partial, _) =>
346 if key.contains(partial, prefix_len) {
347 ValueMatch::IsChild(key.truncate(prefix_len + partial.len()))
348 } else {
349 ValueMatch::NotFound
350 },
351 Node::Branch(children, value) =>
352 match_key_to_branch_node(key, prefix_len, children, value.as_ref()),
353 Node::NibbledBranch(partial, children, value) =>
354 if key.contains(partial, prefix_len) {
355 match_key_to_branch_node(key, prefix_len + partial.len(), children, value.as_ref())
356 } else {
357 ValueMatch::NotFound
358 },
359 }
360}
361
362fn match_key_to_branch_node<'a>(
366 key: &LeftNibbleSlice<'a>,
367 prefix_plus_partial_len: usize,
368 children: &[Option<NodeHandle>; NIBBLE_LENGTH],
369 value: Option<&Value>,
370) -> ValueMatch<'a> {
371 if key.len() == prefix_plus_partial_len {
372 if value.is_none() {
373 ValueMatch::MatchesBranch
374 } else {
375 ValueMatch::NotOmitted
376 }
377 } else {
378 let index =
379 key.at(prefix_plus_partial_len).expect("it's less than prefix.len(); qed") as usize;
380 if children[index].is_some() {
381 ValueMatch::IsChild(key.truncate(prefix_plus_partial_len + 1))
382 } else {
383 ValueMatch::NotFound
384 }
385 }
386}
387
388enum Step<'a> {
389 Descend(LeftNibbleSlice<'a>),
390 UnwindStack,
391}
392
393pub fn verify_proof<'a, L, I, K, V>(
395 root: &<L::Hash as Hasher>::Out,
396 proof: &[Vec<u8>],
397 items: I,
398) -> Result<(), Error<TrieHash<L>, CError<L>>>
399where
400 L: TrieLayout,
401 I: IntoIterator<Item = &'a (K, Option<V>)>,
402 K: 'a + AsRef<[u8]>,
403 V: 'a + AsRef<[u8]>,
404{
405 let mut items = items
407 .into_iter()
408 .map(|(k, v)| (k.as_ref(), v.as_ref().map(|v| v.as_ref())))
409 .collect::<Vec<_>>();
410 items.sort();
411
412 if items.is_empty() {
413 return if proof.is_empty() { Ok(()) } else { Err(Error::ExtraneousNode) }
414 }
415
416 for i in 1..items.len() {
418 if items[i].0 == items[i - 1].0 {
419 return Err(Error::DuplicateKey(items[i].0.to_vec()))
420 }
421 }
422
423 let mut proof_iter = proof.iter().map(|i| i.as_slice());
425 let mut items_iter = items.into_iter().peekable();
426
427 let mut stack: Vec<StackEntry<L>> = Vec::new();
430
431 let root_node = match proof_iter.next() {
432 Some(node) => node,
433 None => return Err(Error::IncompleteProof),
434 };
435 let mut last_entry = StackEntry::<L>::new(root_node, LeftNibbleSlice::new(&[]), false)?;
436
437 loop {
438 match last_entry.advance_item(&mut items_iter)? {
440 Step::Descend(child_prefix) => {
441 let next_entry = last_entry.advance_child_index(child_prefix, &mut proof_iter)?;
442 stack.push(last_entry);
443 last_entry = next_entry;
444 },
445 Step::UnwindStack => {
446 let is_inline = last_entry.is_inline;
447 let node_data = last_entry.encode_node()?;
448
449 let child_ref = if is_inline {
450 if node_data.len() > L::Hash::LENGTH {
451 return Err(Error::InvalidChildReference(node_data))
452 }
453 let mut hash = <TrieHash<L>>::default();
454 hash.as_mut()[..node_data.len()].copy_from_slice(node_data.as_ref());
455 ChildReference::Inline(hash, node_data.len())
456 } else {
457 let hash = L::Hash::hash(&node_data);
458 ChildReference::Hash(hash)
459 };
460
461 if let Some(entry) = stack.pop() {
462 last_entry = entry;
463 last_entry.children[last_entry.child_index] = Some(child_ref);
464 last_entry.child_index += 1;
465 } else {
466 if proof_iter.next().is_some() {
467 return Err(Error::ExtraneousNode)
468 }
469 let computed_root = match child_ref {
470 ChildReference::Hash(hash) => hash,
471 ChildReference::Inline(_, _) =>
472 panic!("the bottom item on the stack has is_inline = false; qed"),
473 };
474 if computed_root != *root {
475 return Err(Error::RootMismatch(computed_root))
476 }
477 break
478 }
479 },
480 }
481 }
482
483 Ok(())
484}