use cfg_if::cfg_if;
cfg_if! {
if #[cfg(test)] {
pub const CHECK_LOADED_SNAPSHOT_MPT_NODE: bool = true;
} else {
pub const CHECK_LOADED_SNAPSHOT_MPT_NODE: bool = false;
}
}
pub type SnapshotMptDbValue = Box<[u8]>;
#[derive(Clone, Default, Debug)]
pub struct SnapshotMptNode(pub VanillaTrieNode<SubtreeMerkleWithSize>);
#[derive(Copy, Clone, PartialEq, Debug, Default)]
pub struct SubtreeMerkleWithSize {
pub merkle: MerkleHash,
pub subtree_size: u64,
pub delta_subtree_size: u64,
}
pub trait SnapshotMptTraitRead: AsSnapshotMptTraitRead {
fn get_merkle_root(&self) -> MerkleHash;
fn load_node(
&mut self, path: &dyn CompressedPathTrait,
) -> Result<Option<SnapshotMptNode>>;
}
pub trait AsSnapshotMptTraitRead {
fn as_readonly(&mut self) -> &mut dyn SnapshotMptTraitRead;
}
impl<T: SnapshotMptTraitRead> AsSnapshotMptTraitRead for T {
fn as_readonly(&mut self) -> &mut dyn SnapshotMptTraitRead { self }
}
pub trait SnapshotMptTraitReadAndIterate: SnapshotMptTraitRead {
fn iterate_subtree_trie_nodes_without_root(
&mut self, path: &dyn CompressedPathTrait,
) -> Result<Box<dyn SnapshotMptIteraterTrait + '_>>;
}
pub trait SnapshotMptTraitRw: SnapshotMptTraitReadAndIterate {
fn delete_node(&mut self, path: &dyn CompressedPathTrait) -> Result<()>;
fn write_node(
&mut self, path: &dyn CompressedPathTrait, trie_node: &SnapshotMptNode,
) -> Result<()>;
}
pub trait SnapshotMptIteraterTrait:
FallibleIterator<Item = (CompressedPathRaw, SnapshotMptNode), Error = Error>
{
}
impl<
T: FallibleIterator<
Item = (CompressedPathRaw, SnapshotMptNode),
Error = Error,
>,
> SnapshotMptIteraterTrait for T
{
}
impl SnapshotMptNode {
pub const NO_CHILD: SubtreeMerkleWithSize = SubtreeMerkleWithSize {
merkle: MERKLE_NULL_NODE,
subtree_size: 0,
delta_subtree_size: 0,
};
pub fn is_valid(&self, path_to_node: &dyn CompressedPathTrait) -> bool {
let mut valid = true;
let children_merkles = self.get_children_merkles();
let merkle_hash = self.compute_merkle(
children_merkles.as_ref(),
CompressedPathRaw::second_nibble(
self.compressed_path_ref().path_mask(),
) != CompressedPathRaw::NO_MISSING_NIBBLE,
);
if self.get_merkle().ne(&merkle_hash) {
error!(
"merkle hash mismatch, expected {:?}, got {:?}, path_to_node {:?}",
merkle_hash, self.get_merkle(), path_to_node,
);
valid = false;
}
let actual_children_count = children_merkles.as_ref().map_or(0, |v| {
v.iter().filter(|&x| x.ne(&MERKLE_NULL_NODE)).count()
});
if self.get_children_count() as usize != actual_children_count {
error!(
"children count is wrong: expected {} got {}",
actual_children_count,
self.get_children_count(),
);
valid = false;
}
if path_to_node.path_size() > 0
&& !self.has_value()
&& self.get_children_count() <= 1
{
error!(
"node should not exists due to path compressing rule, path_to_node {:?}, {:?}",
path_to_node, self
);
valid = false
}
valid
}
pub fn load_rlp_and_check(
rlp_bytes: &[u8], path_to_node: &dyn CompressedPathTrait,
) -> Result<Self> {
let node = Self(Rlp::new(rlp_bytes).as_val()?);
if CHECK_LOADED_SNAPSHOT_MPT_NODE {
node.is_valid(path_to_node);
}
Ok(node)
}
pub fn subtree_size(&self, full_path: &dyn CompressedPathTrait) -> u64 {
Self::initial_subtree_size(&self.0, full_path)
}
fn initial_subtree_size(
node: &VanillaTrieNode<SubtreeMerkleWithSize>,
full_path: &dyn CompressedPathTrait,
) -> u64 {
let mut size = match node.value_as_slice().into_option() {
None => 0,
Some(value) => {
rlp_key_value_len(full_path.path_size(), value.len())
}
};
for (
_child_index,
&SubtreeMerkleWithSize {
ref subtree_size, ..
},
) in node.get_children_table_ref().iter()
{
size += subtree_size;
}
size
}
pub fn get_children_merkles(&self) -> MaybeMerkleTable {
if self.get_children_count() > 0 {
let mut merkle_table = Some(
[ChildrenTableItem::<MerkleHash>::no_child().clone();
CHILDREN_COUNT],
);
for (child_index, &SubtreeMerkleWithSize { ref merkle, .. }) in
self.get_children_table_ref().iter()
{
merkle_table.as_mut().unwrap()[child_index as usize] = *merkle;
}
merkle_table
} else {
None
}
}
pub fn get_merkle_hash_wo_compressed_path(&self) -> MerkleHash {
compute_node_merkle(
self.get_children_merkles().as_ref(),
self.0.value_as_slice().into_option(),
)
}
}
impl Decodable for SnapshotMptNode {
fn decode(rlp: &Rlp) -> std::result::Result<Self, DecoderError> {
Ok(Self(rlp.as_val()?))
}
}
impl Deref for SnapshotMptNode {
type Target = VanillaTrieNode<SubtreeMerkleWithSize>;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl DerefMut for SnapshotMptNode {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}
impl Decodable for SubtreeMerkleWithSize {
fn decode(rlp: &Rlp) -> std::result::Result<Self, DecoderError> {
Ok(Self {
merkle: rlp.val_at(0)?,
subtree_size: rlp.val_at::<u64>(1)?,
delta_subtree_size: rlp.val_at::<u64>(2)?,
})
}
}
impl Encodable for SubtreeMerkleWithSize {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(3)
.append(&self.merkle)
.append(&self.subtree_size)
.append(&self.delta_subtree_size);
}
}
impl NodeRefTrait for SubtreeMerkleWithSize {}
impl DefaultChildrenItem<SubtreeMerkleWithSize>
for ChildrenTableItem<SubtreeMerkleWithSize>
{
fn no_child() -> &'static SubtreeMerkleWithSize {
&SnapshotMptNode::NO_CHILD
}
}
use super::super::impls::{
errors::*,
merkle_patricia_trie::{
merkle::{compute_node_merkle, MaybeMerkleTable},
mpt_cursor::rlp_key_value_len,
ChildrenTableItem, CompressedPathRaw, CompressedPathTrait,
DefaultChildrenItem, NodeRefTrait, TrieNodeTrait, VanillaTrieNode,
CHILDREN_COUNT,
},
};
use fallible_iterator::FallibleIterator;
use primitives::{MerkleHash, MERKLE_NULL_NODE};
use rlp::*;
use std::ops::{Deref, DerefMut};