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