cfx_storage/impls/snapshot_sync/offer/
mpt_slicer.rs

1// Copyright 2019 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
5pub struct MptSlicer<'a> {
6    cursor: MptCursor<
7        &'a mut dyn SnapshotMptTraitRead,
8        BasicPathNode<&'a mut dyn SnapshotMptTraitRead>,
9    >,
10}
11
12impl<'a> MptSlicer<'a> {
13    pub fn new(mpt: &'a mut dyn SnapshotMptTraitRead) -> Result<Self> {
14        let mut cursor = MptCursor::new(mpt);
15        cursor.load_root()?;
16        Ok(Self { cursor })
17    }
18
19    pub fn new_from_key(
20        mpt: &'a mut dyn SnapshotMptTraitRead, key: &[u8],
21    ) -> Result<Self> {
22        let mut slicer = Self::new(mpt)?;
23        slicer.cursor.open_path_for_key::<access_mode::Read>(key)?;
24        Ok(slicer)
25    }
26
27    pub fn to_proof(&self) -> TrieProof { self.cursor.to_proof() }
28
29    pub fn get_range_end_key(&self) -> Option<&[u8]> {
30        // The cursor stops at the key which just exceed,the rlp_size_limit,
31        // or at the root node.
32        let key = self
33            .cursor
34            .get_path_nodes()
35            .last()
36            .unwrap()
37            .get_path_to_node()
38            .path_slice();
39        if key.len() == 0 {
40            None
41        } else {
42            Some(key)
43        }
44    }
45
46    pub fn advance(&mut self, mut rlp_size_limit: u64) -> Result<()> {
47        let current_node = self.cursor.current_node_mut();
48        // First, check the value of this node, if we are the first time
49        // visiting this node.
50        if current_node.next_child_index == 0 {
51            let maybe_value = current_node.value_as_slice();
52            match maybe_value {
53                MptValue::Some(value) => {
54                    let key_value_size = rlp_key_value_len(
55                        current_node.get_path_to_node().path_size(),
56                        value.len(),
57                    );
58                    if rlp_size_limit <= key_value_size {
59                        return Ok(());
60                    } else {
61                        rlp_size_limit -= key_value_size;
62                    }
63                }
64                _ => {}
65            }
66        }
67
68        for (
69            this_child_index,
70            &SubtreeMerkleWithSize {
71                ref subtree_size, ..
72            },
73        ) in current_node
74            .trie_node
75            .get_children_table_ref()
76            .iter()
77            .set_start_index(current_node.next_child_index)
78        {
79            if *subtree_size <= rlp_size_limit {
80                rlp_size_limit -= *subtree_size;
81            } else {
82                let child_node = unsafe {
83                    // Mute Rust borrow checker because there is no way
84                    // around. It's actually safe to open_child_index while
85                    // we immutably borrows the trie_node, because
86                    // open_child_index won't modify
87                    // trie_node.
88                    &mut *(current_node
89                        as *const BasicPathNode<
90                            &'a mut dyn SnapshotMptTraitRead,
91                        >
92                        as *mut BasicPathNode<&'a mut dyn SnapshotMptTraitRead>)
93                }
94                .open_child_index(this_child_index)?
95                // Unwrap is fine because the child is guaranteed to exist.
96                .unwrap();
97
98                self.cursor.push_node(child_node);
99                return self.advance(rlp_size_limit);
100            }
101        }
102
103        // Pop-up because subtree isn't large enough.
104        if rlp_size_limit > 0 && self.cursor.get_path_nodes().len() > 1 {
105            self.cursor.pop_one_node()?;
106            return self.advance(rlp_size_limit);
107        }
108
109        Ok(())
110    }
111}
112
113use super::super::super::{
114    super::{
115        storage_db::snapshot_mpt::{
116            SnapshotMptTraitRead, SubtreeMerkleWithSize,
117        },
118        utils::access_mode,
119    },
120    errors::*,
121    merkle_patricia_trie::{mpt_cursor::*, *},
122};
123use primitives::MptValue;