nam_sparse_merkle_tree/
proof_ics23.rs

1use ics23::{ExistenceProof, HashOp, InnerOp, InnerSpec, LeafOp, LengthOp, ProofSpec};
2
3use crate::collections::VecDeque;
4use crate::error::{Error, Result};
5use crate::{Key, MerkleProof, H256, TREE_HEIGHT, traits::Value};
6
7pub fn convert<K, V, const N: usize>(
8    merkle_proof: MerkleProof,
9    key: &K,
10    value: &V,
11    hash_op: HashOp,
12) -> Result<ExistenceProof>
13where
14    K: Key<N>,
15    V: Value,
16{
17    let (leaves_path, proof) = merkle_proof.take();
18    let mut merge_heights: VecDeque<_> = leaves_path
19        .get(0)
20        .expect("The heights should exist")
21        .clone()
22        .into();
23    let mut proof: VecDeque<_> = proof.into();
24    let mut cur_key = **key;
25    let mut height = 0;
26    let mut path = Vec::new();
27    while !proof.is_empty() {
28        if height == TREE_HEIGHT {
29            if !proof.is_empty() {
30                return Err(Error::CorruptedProof);
31            }
32            break;
33        }
34
35        // check the height is valid
36        let merge_height = merge_heights.front().map(|h| *h as usize).unwrap_or(height);
37        if height != merge_height {
38            // skip the heights
39            height = merge_height;
40            continue;
41        }
42
43        // get a proof
44        let (sibling, sibling_height) = proof.pop_front().expect("no proof");
45        if height < sibling_height as usize {
46            // skip heights
47            height = sibling_height as usize;
48        }
49        let inner_op = get_inner_op(hash_op, &sibling, cur_key.get_bit(height));
50        path.push(inner_op);
51
52        merge_heights.pop_front();
53        cur_key = cur_key.parent_path(height);
54        height += 1;
55    }
56
57    Ok(ExistenceProof {
58        key: key.to_vec(),
59        value: value.as_slice().to_vec(),
60        leaf: Some(get_leaf_op(hash_op)),
61        path,
62    })
63}
64
65pub fn get_spec(hash_op: HashOp) -> ProofSpec {
66    ProofSpec {
67        leaf_spec: Some(get_leaf_op(hash_op)),
68        inner_spec: Some(get_inner_spec(hash_op)),
69        max_depth: TREE_HEIGHT as i32,
70        min_depth: 0,
71        prehash_key_before_comparison: false,
72    }
73}
74
75fn get_leaf_op(hash_op: HashOp) -> LeafOp {
76    LeafOp {
77        hash: hash_op.into(),
78        prehash_key: HashOp::NoHash.into(),
79        prehash_value: HashOp::NoHash.into(),
80        length: LengthOp::NoPrefix.into(),
81        prefix: H256::zero().as_slice().to_vec(),
82    }
83}
84
85fn get_inner_op(hash_op: HashOp, sibling: &H256, is_right_node: bool) -> InnerOp {
86    let node = sibling.as_slice().to_vec();
87    let (prefix, suffix) = if is_right_node {
88        (node, vec![])
89    } else {
90        (vec![], node)
91    };
92    InnerOp {
93        hash: hash_op.into(),
94        prefix,
95        suffix,
96    }
97}
98
99fn get_inner_spec(hash_op: HashOp) -> InnerSpec {
100    InnerSpec {
101        child_order: vec![0, 1],
102        child_size: 32,
103        min_prefix_length: 0,
104        max_prefix_length: 32,
105        empty_child: vec![],
106        hash: hash_op.into(),
107    }
108}