use super::types::*;
use radix_common::crypto::Hash;
use radix_rust::prelude::*;
const SANITY_NIBBLE_LIMIT: usize = 1000;
pub struct JellyfishMerkleTree<'a, R: ?Sized, P> {
reader: &'a R,
phantom_value: PhantomData<P>,
}
impl<'a, R: 'a + TreeReader<P> + ?Sized, P: Clone> JellyfishMerkleTree<'a, R, P> {
pub fn new(reader: &'a R) -> Self {
Self {
reader,
phantom_value: PhantomData,
}
}
fn get_hash(
node_key: &TreeNodeKey,
node: &Node<P>,
hash_cache: &Option<&HashMap<NibblePath, Hash>>,
) -> Hash {
if let Some(cache) = hash_cache {
match cache.get(node_key.nibble_path()) {
Some(hash) => *hash,
None => unreachable!("{:?} can not be found in hash cache", node_key),
}
} else {
node.hash()
}
}
pub fn batch_put_value_set(
&self,
value_set: BTreeMap<LeafKey, Option<(Hash, P)>>,
node_hashes: Option<&HashMap<NibblePath, Hash>>,
persisted_version: Option<Version>,
version: Version,
) -> Result<(Hash, TreeUpdateBatch<P>), StorageError> {
let deduped_and_sorted_kvs = value_set
.iter()
.map(|(key, entry)| (key, entry.as_ref()))
.collect::<Vec<_>>();
let mut batch = TreeUpdateBatch::new();
let root_node_opt = if let Some(persisted_version) = persisted_version {
self.batch_insert_at(
&TreeNodeKey::new_empty_path(persisted_version),
version,
deduped_and_sorted_kvs.as_slice(),
0,
&node_hashes,
&mut batch,
)
} else {
self.batch_update_subtree(
&TreeNodeKey::new_empty_path(version),
version,
deduped_and_sorted_kvs.as_slice(),
0,
&node_hashes,
&mut batch,
)
}?;
let node_key = TreeNodeKey::new_empty_path(version);
let root_hash = if let Some(root_node) = root_node_opt {
let hash = root_node.hash();
batch.put_node(node_key, root_node);
hash
} else {
batch.put_node(node_key, Node::Null);
SPARSE_MERKLE_PLACEHOLDER_HASH
};
Ok((root_hash, batch))
}
fn batch_insert_at(
&self,
node_key: &TreeNodeKey,
version: Version,
kvs: &[(&LeafKey, Option<&(Hash, P)>)],
depth: usize,
hash_cache: &Option<&HashMap<NibblePath, Hash>>,
batch: &mut TreeUpdateBatch<P>,
) -> Result<Option<Node<P>>, StorageError> {
let node = self.reader.get_node(node_key)?;
batch.put_stale_node(node_key.clone(), version, &node);
match node {
Node::Internal(internal_node) => {
let range_iter = NibbleRangeIterator::new(kvs, depth);
let new_children: Vec<_> = range_iter
.map(|(left, right)| {
self.insert_at_child(
node_key,
&internal_node,
version,
kvs,
left,
right,
depth,
hash_cache,
batch,
)
})
.collect::<Result<_, StorageError>>()?;
let mut old_children: Children = internal_node.into();
let mut new_created_children: HashMap<Nibble, Node<P>> = hash_map_new();
for (child_nibble, child_option) in new_children {
if let Some(child) = child_option {
new_created_children.insert(child_nibble, child);
} else {
old_children.remove(&child_nibble);
}
}
if old_children.is_empty() && new_created_children.is_empty() {
return Ok(None);
} else if old_children.len() <= 1 && new_created_children.len() <= 1 {
if let Some((new_nibble, new_child)) = new_created_children.iter().next() {
if let Some((old_nibble, _old_child)) = old_children.iter().next() {
if old_nibble == new_nibble && new_child.is_leaf() {
return Ok(Some(new_child.clone()));
}
} else if new_child.is_leaf() {
return Ok(Some(new_child.clone()));
}
} else {
let (old_child_nibble, old_child) =
old_children.iter().next().expect("must exist");
if old_child.is_leaf() {
let old_child_node_key =
node_key.gen_child_node_key(old_child.version, *old_child_nibble);
let old_child_node = self.reader.get_node(&old_child_node_key)?;
batch.put_stale_node(old_child_node_key, version, &old_child_node);
return Ok(Some(old_child_node));
}
}
}
let mut new_children = old_children;
for (child_index, new_child_node) in new_created_children {
let new_child_node_key = node_key.gen_child_node_key(version, child_index);
new_children.insert(
child_index,
Child::new(
Self::get_hash(&new_child_node_key, &new_child_node, hash_cache),
version,
new_child_node.node_type(),
),
);
batch.put_node(new_child_node_key, new_child_node);
}
let new_internal_node = InternalNode::new(new_children);
Ok(Some(new_internal_node.into()))
}
Node::Leaf(leaf_node) => self.batch_update_subtree_with_existing_leaf(
node_key, version, leaf_node, kvs, depth, hash_cache, batch,
),
Node::Null => {
assert_eq!(depth, 0, "Null node can only exist at depth 0");
self.batch_update_subtree(node_key, version, kvs, 0, hash_cache, batch)
}
}
}
#[allow(clippy::too_many_arguments)]
fn insert_at_child(
&self,
node_key: &TreeNodeKey,
internal_node: &InternalNode,
version: Version,
kvs: &[(&LeafKey, Option<&(Hash, P)>)],
left: usize,
right: usize,
depth: usize,
hash_cache: &Option<&HashMap<NibblePath, Hash>>,
batch: &mut TreeUpdateBatch<P>,
) -> Result<(Nibble, Option<Node<P>>), StorageError> {
let child_index = kvs[left].0.get_nibble(depth);
let child = internal_node.child(child_index);
let new_child_node_option = match child {
Some(child) => self.batch_insert_at(
&node_key.gen_child_node_key(child.version, child_index),
version,
&kvs[left..=right],
depth + 1,
hash_cache,
batch,
)?,
None => self.batch_update_subtree(
&node_key.gen_child_node_key(version, child_index),
version,
&kvs[left..=right],
depth + 1,
hash_cache,
batch,
)?,
};
Ok((child_index, new_child_node_option))
}
#[allow(clippy::too_many_arguments)]
fn batch_update_subtree_with_existing_leaf(
&self,
node_key: &TreeNodeKey,
version: Version,
existing_leaf_node: LeafNode<P>,
kvs: &[(&LeafKey, Option<&(Hash, P)>)],
depth: usize,
hash_cache: &Option<&HashMap<NibblePath, Hash>>,
batch: &mut TreeUpdateBatch<P>,
) -> Result<Option<Node<P>>, StorageError> {
let existing_leaf_key = existing_leaf_node.leaf_key();
if kvs.len() == 1 && kvs[0].0 == existing_leaf_key {
if let (key, Some((value_hash, payload))) = kvs[0] {
let new_leaf_node =
Node::new_leaf(key.clone(), *value_hash, payload.clone(), version);
Ok(Some(new_leaf_node))
} else {
Ok(None)
}
} else {
let existing_leaf_bucket = existing_leaf_key.get_nibble(depth);
let mut isolated_existing_leaf = true;
let mut children = vec![];
for (left, right) in NibbleRangeIterator::new(kvs, depth) {
let child_index = kvs[left].0.get_nibble(depth);
let child_node_key = node_key.gen_child_node_key(version, child_index);
if let Some(new_child_node) = if existing_leaf_bucket == child_index {
isolated_existing_leaf = false;
self.batch_update_subtree_with_existing_leaf(
&child_node_key,
version,
existing_leaf_node.clone(),
&kvs[left..=right],
depth + 1,
hash_cache,
batch,
)?
} else {
self.batch_update_subtree(
&child_node_key,
version,
&kvs[left..=right],
depth + 1,
hash_cache,
batch,
)?
} {
children.push((child_index, new_child_node));
}
}
if isolated_existing_leaf {
children.push((existing_leaf_bucket, existing_leaf_node.into()));
}
if children.is_empty() {
Ok(None)
} else if children.len() == 1 && children[0].1.is_leaf() {
let (_, child) = children.pop().expect("Must exist");
Ok(Some(child))
} else {
let new_internal_node = InternalNode::new(
children
.into_iter()
.map(|(child_index, new_child_node)| {
let new_child_node_key =
node_key.gen_child_node_key(version, child_index);
let result = (
child_index,
Child::new(
Self::get_hash(
&new_child_node_key,
&new_child_node,
hash_cache,
),
version,
new_child_node.node_type(),
),
);
batch.put_node(new_child_node_key, new_child_node);
result
})
.collect(),
);
Ok(Some(new_internal_node.into()))
}
}
}
fn batch_update_subtree(
&self,
node_key: &TreeNodeKey,
version: Version,
kvs: &[(&LeafKey, Option<&(Hash, P)>)],
depth: usize,
hash_cache: &Option<&HashMap<NibblePath, Hash>>,
batch: &mut TreeUpdateBatch<P>,
) -> Result<Option<Node<P>>, StorageError> {
if kvs.len() == 1 {
if let (key, Some((value_hash, payload))) = kvs[0] {
let new_leaf_node =
Node::new_leaf(key.clone(), *value_hash, payload.clone(), version);
Ok(Some(new_leaf_node))
} else {
Ok(None)
}
} else {
let mut children = vec![];
for (left, right) in NibbleRangeIterator::new(kvs, depth) {
let child_index = kvs[left].0.get_nibble(depth);
let child_node_key = node_key.gen_child_node_key(version, child_index);
if let Some(new_child_node) = self.batch_update_subtree(
&child_node_key,
version,
&kvs[left..=right],
depth + 1,
hash_cache,
batch,
)? {
children.push((child_index, new_child_node))
}
}
if children.is_empty() {
Ok(None)
} else if children.len() == 1 && children[0].1.is_leaf() {
let (_, child) = children.pop().expect("Must exist");
Ok(Some(child))
} else {
let new_internal_node = InternalNode::new(
children
.into_iter()
.map(|(child_index, new_child_node)| {
let new_child_node_key =
node_key.gen_child_node_key(version, child_index);
let result = (
child_index,
Child::new(
Self::get_hash(
&new_child_node_key,
&new_child_node,
hash_cache,
),
version,
new_child_node.node_type(),
),
);
batch.put_node(new_child_node_key, new_child_node);
result
})
.collect(),
);
Ok(Some(new_internal_node.into()))
}
}
}
#[allow(clippy::type_complexity)]
pub fn get_with_proof(
&self,
key: &LeafKey,
version: Version,
) -> Result<(Option<(Hash, P, Version)>, SparseMerkleProof), StorageError> {
self.get_with_proof_ext(key, version)
.map(|(value, proof_ext)| (value, proof_ext.into()))
}
#[allow(clippy::type_complexity)]
pub fn get_with_proof_ext(
&self,
key: &LeafKey,
version: Version,
) -> Result<(Option<(Hash, P, Version)>, SparseMerkleProofExt), StorageError> {
let mut next_node_key = TreeNodeKey::new_empty_path(version);
let mut siblings = vec![];
let nibble_path = NibblePath::new_even(key.bytes.clone());
let mut nibble_iter = nibble_path.nibbles();
for _nibble_depth in 0..SANITY_NIBBLE_LIMIT {
let next_node = self.reader.get_node(&next_node_key)?;
match next_node {
Node::Internal(internal_node) => {
let queried_child_index =
nibble_iter.next().ok_or(StorageError::InconsistentState)?;
let (child_node_key, mut siblings_in_internal) = internal_node
.get_child_with_siblings(
&next_node_key,
queried_child_index,
Some(self.reader),
)?;
siblings.append(&mut siblings_in_internal);
next_node_key = match child_node_key {
Some(node_key) => node_key,
None => {
return Ok((
None,
SparseMerkleProofExt::new(None, {
siblings.reverse();
siblings
}),
))
}
};
}
Node::Leaf(leaf_node) => {
return Ok((
if leaf_node.leaf_key() == key {
Some((
leaf_node.value_hash(),
leaf_node.payload().clone(),
leaf_node.version(),
))
} else {
None
},
SparseMerkleProofExt::new(Some(leaf_node.into()), {
siblings.reverse();
siblings
}),
));
}
Node::Null => {
return Ok((None, SparseMerkleProofExt::new(None, vec![])));
}
}
}
Err(StorageError::InconsistentState)
}
pub fn get_range_proof(
&self,
rightmost_key_to_prove: &LeafKey,
version: Version,
) -> Result<SparseMerkleRangeProof, StorageError> {
let (leaf, proof) = self.get_with_proof(rightmost_key_to_prove, version)?;
assert!(leaf.is_some(), "rightmost_key_to_prove must exist.");
let siblings = proof
.siblings()
.iter()
.rev()
.zip(rightmost_key_to_prove.iter_bits())
.filter_map(|(sibling, bit)| {
if !bit {
Some(*sibling)
} else {
None
}
})
.rev()
.collect();
Ok(SparseMerkleRangeProof::new(siblings))
}
fn get_root_node(&self, version: Version) -> Result<Node<P>, StorageError> {
let root_node_key = TreeNodeKey::new_empty_path(version);
self.reader.get_node(&root_node_key)
}
pub fn get_root_hash(&self, version: Version) -> Result<Hash, StorageError> {
self.get_root_node(version).map(|n| n.hash())
}
pub fn get_leaf_count(&self, version: Version) -> Result<usize, StorageError> {
self.get_root_node(version).map(|n| n.leaf_count())
}
pub fn get_all_nodes_referenced(
&self,
key: TreeNodeKey,
) -> Result<Vec<TreeNodeKey>, StorageError> {
let mut out_keys = vec![];
self.get_all_nodes_referenced_impl(key, &mut out_keys)?;
Ok(out_keys)
}
fn get_all_nodes_referenced_impl(
&self,
key: TreeNodeKey,
out_keys: &mut Vec<TreeNodeKey>,
) -> Result<(), StorageError> {
match self.reader.get_node(&key)? {
Node::Internal(internal_node) => {
for (child_nibble, child) in internal_node.children_sorted() {
self.get_all_nodes_referenced_impl(
key.gen_child_node_key(child.version, *child_nibble),
out_keys,
)?;
}
}
Node::Leaf(_) | Node::Null => {}
};
out_keys.push(key);
Ok(())
}
}
struct NibbleRangeIterator<'a, P> {
sorted_kvs: &'a [(&'a LeafKey, P)],
nibble_idx: usize,
pos: usize,
}
impl<'a, P> NibbleRangeIterator<'a, P> {
fn new(sorted_kvs: &'a [(&'a LeafKey, P)], nibble_idx: usize) -> Self {
NibbleRangeIterator {
sorted_kvs,
nibble_idx,
pos: 0,
}
}
}
impl<'a, P> Iterator for NibbleRangeIterator<'a, P> {
type Item = (usize, usize);
fn next(&mut self) -> Option<Self::Item> {
let left = self.pos;
if self.pos < self.sorted_kvs.len() {
let cur_nibble = self.sorted_kvs[left].0.get_nibble(self.nibble_idx);
let (mut i, mut j) = (left, self.sorted_kvs.len() - 1);
while i < j {
let mid = j - (j - i) / 2;
if self.sorted_kvs[mid].0.get_nibble(self.nibble_idx) > cur_nibble {
j = mid - 1;
} else {
i = mid;
}
}
self.pos = i + 1;
Some((left, i))
} else {
None
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct TreeUpdateBatch<P> {
pub node_batch: Vec<Vec<(TreeNodeKey, Node<P>)>>,
pub stale_node_index_batch: Vec<Vec<StaleNodeIndex>>,
pub num_new_leaves: usize,
pub num_stale_leaves: usize,
}
impl<P: Clone> TreeUpdateBatch<P> {
pub fn new() -> Self {
Self {
node_batch: vec![vec![]],
stale_node_index_batch: vec![vec![]],
num_new_leaves: 0,
num_stale_leaves: 0,
}
}
fn inc_num_new_leaves(&mut self) {
self.num_new_leaves += 1;
}
fn inc_num_stale_leaves(&mut self) {
self.num_stale_leaves += 1;
}
pub fn put_node(&mut self, node_key: TreeNodeKey, node: Node<P>) {
if node.is_leaf() {
self.inc_num_new_leaves();
}
self.node_batch[0].push((node_key, node))
}
pub fn put_stale_node(
&mut self,
node_key: TreeNodeKey,
stale_since_version: Version,
node: &Node<P>,
) {
if node.is_leaf() {
self.inc_num_stale_leaves();
}
self.stale_node_index_batch[0].push(StaleNodeIndex {
node_key,
stale_since_version,
});
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct StaleNodeIndex {
pub stale_since_version: Version,
pub node_key: TreeNodeKey,
}