cfx_storage/impls/merkle_patricia_trie/
simple_mpt.rs

1// Copyright 2020 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5fn min_repr_bytes(number_of_keys: usize) -> usize {
6    let mut largest_value = match number_of_keys {
7        n if n == 0 => return 0,
8        n if n == 1 => return 1,
9        n => n - 1,
10    };
11
12    let mut min_repr_bytes = 0;
13
14    while largest_value != 0 {
15        min_repr_bytes += 1;
16        largest_value >>= 8;
17    }
18
19    min_repr_bytes
20}
21
22fn to_index_bytes(mut index: usize, len: usize) -> Vec<u8> {
23    let mut bytes = vec![0u8; len];
24
25    for i in (0..len).rev() {
26        bytes[i] = index as u8;
27        index >>= 8;
28    }
29
30    bytes
31}
32
33/// Given an integer-indexed `SimpleMpt` with `num_keys` elements
34/// stored in it, convert `key` into the corresponding key format.
35pub fn into_simple_mpt_key(key: usize, num_keys: usize) -> Vec<u8> {
36    let key_length = min_repr_bytes(num_keys);
37    to_index_bytes(key, key_length)
38}
39
40pub fn make_simple_mpt(mut values: Vec<Box<[u8]>>) -> SimpleMpt {
41    let mut mpt = SimpleMpt::default();
42    let keys = values.len();
43    let mut mpt_kvs = Vec::with_capacity(keys);
44
45    let index_byte_len = min_repr_bytes(keys);
46
47    for (index, value) in values.drain(..).enumerate() {
48        mpt_kvs.push((to_index_bytes(index, index_byte_len), value));
49    }
50
51    MptMerger::new(None, &mut mpt)
52        .merge(&DumpedMptKvIterator { kv: mpt_kvs })
53        .expect("SimpleMpt does not fail.");
54
55    mpt
56}
57
58pub fn simple_mpt_merkle_root(simple_mpt: &mut SimpleMpt) -> MerkleHash {
59    let maybe_root_node = simple_mpt
60        .load_node(&CompressedPathRaw::default())
61        .expect("SimpleMpt does not fail.");
62    match maybe_root_node {
63        None => MERKLE_NULL_NODE,
64        Some(root_node) => {
65            // if all keys share the same prefix (e.g. 0x00, ..., 0x0f share
66            // the first nibble) then they will all be under the first child of
67            // the root. in this case, we will use this first child as the root.
68            if root_node.get_children_count() == 1 {
69                trace!(
70                    "debug receipts calculation: root node {:?}",
71                    simple_mpt.load_node(
72                        &CompressedPathRaw::new_and_apply_mask(
73                            &[0],
74                            CompressedPathRaw::second_nibble_mask()
75                        )
76                    )
77                );
78
79                root_node.get_child(0).expect("Child 0 must exist").merkle
80            } else {
81                trace!("debug receipts calculation: root node {:?}", root_node);
82                *root_node.get_merkle()
83            }
84        }
85    }
86}
87
88pub fn simple_mpt_proof(
89    simple_mpt: &mut SimpleMpt, access_key: &[u8],
90) -> TrieProof {
91    let mut cursor = MptCursor::<
92        &mut dyn SnapshotMptTraitRead,
93        BasicPathNode<&mut dyn SnapshotMptTraitRead>,
94    >::new(simple_mpt);
95
96    cursor.load_root().expect("load_root should succeed");
97
98    // see comment in `simple_mpt_merkle_root`
99    let remove_root = cursor.current_node_mut().get_children_count() == 1;
100
101    cursor
102        .open_path_for_key::<access_mode::Read>(access_key)
103        .expect("open_path_for_key should succeed");
104
105    let mut proof = cursor.to_proof();
106    cursor.finish().expect("finish should succeed");
107
108    if remove_root {
109        proof = TrieProof::new(proof.get_proof_nodes()[1..].to_vec())
110            .expect("Proof with root removed is still connected");
111    }
112
113    proof
114}
115
116use crate::{
117    impls::merkle_patricia_trie::{
118        mpt_cursor::{BasicPathNode, MptCursor},
119        trie_node::TrieNodeTrait,
120        walk::GetChildTrait,
121        CompressedPathRaw, MptMerger, TrieProof,
122    },
123    storage_db::SnapshotMptTraitRead,
124    tests::DumpedMptKvIterator,
125    utils::access_mode,
126};
127use primitives::{MerkleHash, MERKLE_NULL_NODE};
128
129pub use crate::tests::FakeSnapshotMptDb as SimpleMpt;
130
131#[cfg(test)]
132mod tests {
133    use super::{
134        into_simple_mpt_key, make_simple_mpt, min_repr_bytes,
135        simple_mpt_merkle_root, simple_mpt_proof, MerkleHash,
136    };
137
138    #[test]
139    fn test_min_repr_bytes() {
140        assert_eq!(min_repr_bytes(0x00_00_00_00), 0); // 0
141
142        assert_eq!(min_repr_bytes(0x00_00_00_01), 1); // 1
143        assert_eq!(min_repr_bytes(0x00_00_01_00), 1); // 256
144
145        assert_eq!(min_repr_bytes(0x00_00_01_01), 2); // 257
146        assert_eq!(min_repr_bytes(0x00_01_00_00), 2); // 65536
147
148        assert_eq!(min_repr_bytes(0x00_01_00_01), 3); // 65537
149        assert_eq!(min_repr_bytes(0x01_00_00_00), 3); // 16777216
150    }
151
152    #[test]
153    fn test_into_simple_mpt_key() {
154        assert_eq!(into_simple_mpt_key(0x01, 1), vec![0x01]);
155        assert_eq!(into_simple_mpt_key(0x01, 256), vec![0x01]);
156        assert_eq!(into_simple_mpt_key(0x01, 257), vec![0x00, 0x01]);
157        assert_eq!(into_simple_mpt_key(0x01, 65536), vec![0x00, 0x01]);
158        assert_eq!(into_simple_mpt_key(0x01, 65537), vec![0x00, 0x00, 0x01]);
159    }
160
161    #[test]
162    fn test_empty_simple_mpt() {
163        let mut mpt = make_simple_mpt(vec![]);
164        let root = simple_mpt_merkle_root(&mut mpt);
165
166        assert_eq!(
167            root,
168            "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
169                .parse::<MerkleHash>()
170                .unwrap()
171        );
172    }
173
174    fn check_proofs(num_items: usize, proof_size: Vec<usize>) {
175        // create k-v pairs:
176        // (0x00, 0x00)
177        // (0x01, 0x01)
178        // ...
179
180        let value_from_key = |key| into_simple_mpt_key(key, num_items);
181
182        let values: Vec<Box<[u8]>> = (0..num_items)
183            .map(|k| value_from_key(k).into_boxed_slice())
184            .collect();
185
186        let mut mpt = make_simple_mpt(values);
187        let root = simple_mpt_merkle_root(&mut mpt);
188
189        for k in 0..num_items {
190            let key = into_simple_mpt_key(k, num_items);
191            let proof = simple_mpt_proof(&mut mpt, &key);
192
193            assert!(proof_size.contains(&proof.number_nodes()));
194
195            // proof should be able to verify correct k-v
196            assert!(proof.is_valid_kv(
197                &into_simple_mpt_key(k, num_items),
198                Some(&value_from_key(k)[..]),
199                &root
200            ));
201
202            // proof with incorrect value should fail
203            assert!(!proof.is_valid_kv(
204                &into_simple_mpt_key(k, num_items),
205                Some(&value_from_key(k + 1)[..]),
206                &root
207            ));
208
209            // proof should not be able to verify other values in the trie
210            for other in 0..num_items {
211                if k == other {
212                    continue;
213                }
214
215                assert!(!proof.is_valid_kv(
216                    &into_simple_mpt_key(other, num_items),
217                    Some(&value_from_key(other)[..]),
218                    &root
219                ));
220            }
221        }
222    }
223
224    #[test]
225    #[rustfmt::skip]
226    fn test_simple_mpt_proof() {
227        // number of items: 0x01
228        // keys: 0x00
229        // proof size: 1 (root)
230        check_proofs(0x01, vec![1]);
231
232        // number of items: 0x02
233        // keys: 0x00, 0x01
234        //          ^     ^
235        // proof size: 2 (root + 2nd nibble)
236        check_proofs(0x02, vec![2]);
237
238        // number of items: 0x10
239        // keys: 0x00, 0x01, ..., 0x0f
240        //          ^     ^          ^
241        // proof size: 2 (root + 2nd nibble)
242        check_proofs(0x10, vec![2]);
243
244        // number of items: 0x11
245        // keys: 0x00, 0x01, ..., 0x0f, 0x10
246        // proof size:
247        //   0x00, 0x01, ..., 0x0f -> 3 (root + 1st nibble + 2nd nibble)
248        //     ^^    ^^         ^^
249        //   0x10                  -> 2 (root + 1st nibble)
250        //     ^
251        check_proofs(0x11, vec![2, 3]);
252
253        // number of items: 0x12
254        // keys: 0x00, 0x01, ..., 0x0f, 0x10, 0x11
255        //         ^^    ^^         ^^    ^^    ^^
256        // proof size: 3 (root + 1st nibble + 2nd nibble)
257        check_proofs(0x12, vec![3]);
258
259        // number of items: 0x0100
260        // keys: 0x00, 0x01, ..., 0xff
261        //         ^^    ^^         ^^
262        // proof size: 3 (root + 1st nibble + 2nd nibble)
263        check_proofs(0x0100, vec![3]);
264
265        // number of items: 0x101
266        // keys: [0x00, 0x00], [0x00, 0x01], [0x00, 0x02], ..., [0x01, 0x00]
267        // proof size:
268        //   [0x00, 0x00], ..., [0x00, 0xff] -> 4 (root + 2nd nibble + 3rd nibble + 4th nibble)
269        //       ^    ^^            ^    ^^
270        //   [0x01, 0x00]      -> 2 (root + 2nd nibble)
271        //       ^
272        check_proofs(0x0101, vec![2, 4]);
273    }
274}