use crate::errors::{AkdError, StorageError, TreeNodeError};
#[cfg(feature = "serde_serialization")]
use crate::serialization::{bytes_deserialize_hex, bytes_serialize_hex};
use crate::serialization::{from_digest, to_digest};
use crate::storage::manager::StorageManager;
use crate::storage::types::{DbRecord, StorageType};
use crate::storage::{Database, Storable};
use crate::{node_label::*, Direction, EMPTY_LABEL};
use async_recursion::async_recursion;
use log::debug;
use std::cmp::min;
use std::convert::TryInto;
use std::marker::{Send, Sync};
use winter_crypto::Hasher;
#[derive(Eq, PartialEq, Debug, Copy, Clone, Hash)]
#[cfg_attr(
feature = "serde_serialization",
derive(serde::Deserialize, serde::Serialize)
)]
pub enum NodeType {
Leaf = 1,
Root = 2,
Interior = 3,
}
impl crate::storage::SizeOf for NodeType {
fn size_of(&self) -> usize {
1
}
}
impl NodeType {
pub(crate) fn from_u8(code: u8) -> Self {
match code {
1 => Self::Leaf,
2 => Self::Root,
3 => Self::Interior,
_ => Self::Leaf,
}
}
}
pub(crate) type InsertionNode<'a> = (Direction, &'a mut TreeNode);
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
#[cfg_attr(
feature = "serde_serialization",
derive(serde::Deserialize, serde::Serialize)
)]
#[cfg_attr(feature = "serde_serialization", serde(bound = ""))]
pub struct TreeNodeWithPreviousValue {
pub label: NodeLabel,
pub latest_node: TreeNode,
pub previous_node: Option<TreeNode>,
}
impl crate::storage::SizeOf for TreeNodeWithPreviousValue {
fn size_of(&self) -> usize {
self.label.size_of()
+ self.latest_node.size_of()
+ self.previous_node.as_ref().map_or(8, |v| v.size_of() + 8)
}
}
impl Storable for TreeNodeWithPreviousValue {
type StorageKey = NodeKey;
fn data_type() -> StorageType {
StorageType::TreeNode
}
fn get_id(&self) -> NodeKey {
NodeKey(self.label)
}
fn get_full_binary_key_id(key: &NodeKey) -> Vec<u8> {
let mut result = vec![StorageType::TreeNode as u8];
result.extend_from_slice(&key.0.label_len.to_le_bytes());
result.extend_from_slice(&key.0.label_val);
result
}
fn key_from_full_binary(bin: &[u8]) -> Result<NodeKey, String> {
if bin.len() < 37 {
return Err("Not enough bytes to form a proper key".to_string());
}
if bin[0] != StorageType::TreeNode as u8 {
return Err("Not a tree node key".to_string());
}
let len_bytes: [u8; 4] = bin[1..=4].try_into().expect("Slice with incorrect length");
let val_bytes: [u8; 32] = bin[5..=36].try_into().expect("Slice with incorrect length");
let len = u32::from_le_bytes(len_bytes);
Ok(NodeKey(NodeLabel::new(val_bytes, len)))
}
}
impl TreeNodeWithPreviousValue {
fn determine_node_to_get(&self, target_epoch: u64) -> Result<TreeNode, StorageError> {
if self.latest_node.last_epoch > target_epoch {
if let Some(previous_node) = &self.previous_node {
Ok(previous_node.clone())
} else {
Err(StorageError::NotFound(format!(
"TreeNode {:?} at epoch {}",
NodeKey(self.label),
target_epoch
)))
}
} else {
Ok(self.latest_node.clone())
}
}
#[cfg(feature = "public-tests")]
pub(crate) fn from_tree_node(node: TreeNode) -> Self {
Self {
label: node.label,
latest_node: node,
previous_node: None,
}
}
pub(crate) async fn write_to_storage<S: Database + Send + Sync>(
&self,
storage: &StorageManager<S>,
) -> Result<(), StorageError> {
storage.set(DbRecord::TreeNode(self.clone())).await
}
pub(crate) async fn get_appropriate_tree_node_from_storage<S: Database + Send + Sync>(
storage: &StorageManager<S>,
key: &NodeKey,
target_epoch: u64,
) -> Result<TreeNode, StorageError> {
match storage.get::<Self>(key).await? {
DbRecord::TreeNode(node) => node.determine_node_to_get(target_epoch),
_ => Err(StorageError::NotFound(format!(
"TreeNodeWithPreviousValue {:?}",
key
))),
}
}
pub(crate) async fn batch_get_appropriate_tree_node_from_storage<S: Database + Send + Sync>(
storage: &StorageManager<S>,
keys: &[NodeKey],
target_epoch: u64,
) -> Result<Vec<TreeNode>, StorageError> {
let node_records: Vec<DbRecord> = storage.batch_get::<Self>(keys).await?;
let mut nodes = Vec::<TreeNode>::new();
for node in node_records.into_iter() {
if let DbRecord::TreeNode(node) = node {
let correct_node = node.determine_node_to_get(target_epoch)?;
nodes.push(correct_node);
} else {
return Err(StorageError::NotFound(
"Batch retrieve returned types <> TreeNodeWithPreviousValue".to_string(),
));
}
}
Ok(nodes)
}
}
#[derive(Debug, Eq, PartialEq, Hash)]
#[cfg_attr(
feature = "serde_serialization",
derive(serde::Deserialize, serde::Serialize)
)]
#[cfg_attr(feature = "serde_serialization", serde(bound = ""))]
pub struct TreeNode {
pub label: NodeLabel,
pub last_epoch: u64,
pub least_descendant_ep: u64,
pub parent: NodeLabel, pub node_type: NodeType, pub left_child: Option<NodeLabel>,
pub right_child: Option<NodeLabel>,
#[cfg_attr(
feature = "serde_serialization",
serde(serialize_with = "bytes_serialize_hex")
)]
#[cfg_attr(
feature = "serde_serialization",
serde(deserialize_with = "bytes_deserialize_hex")
)]
pub hash: [u8; 32],
}
impl crate::storage::SizeOf for TreeNode {
fn size_of(&self) -> usize {
self.label.size_of()
+ std::mem::size_of::<u64>() * 2
+ self.parent.size_of()
+ self.node_type.size_of()
+ self.left_child.as_ref().map_or(8, |v| v.size_of() + 8)
+ self.right_child.as_ref().map_or(8, |v| v.size_of() + 8)
+ 32
}
}
impl TreeNode {
pub(crate) async fn write_to_storage<S: Database + Send + Sync>(
&self,
storage: &StorageManager<S>,
) -> Result<(), StorageError> {
self.write_to_storage_impl(storage, false).await
}
async fn write_to_storage_impl<S: Database + Send + Sync>(
&self,
storage: &StorageManager<S>,
is_new_node: bool,
) -> Result<(), StorageError> {
let target_epoch = match self.last_epoch {
e if e > 0 => e - 1,
other => other,
};
let previous = if is_new_node {
None
} else {
match TreeNodeWithPreviousValue::get_appropriate_tree_node_from_storage(
storage,
&NodeKey(self.label),
target_epoch,
)
.await
{
Ok(p) => Some(p),
Err(StorageError::NotFound(_)) => None,
Err(other) => return Err(other),
}
};
let left_shifted = TreeNodeWithPreviousValue {
label: self.label,
latest_node: self.clone(),
previous_node: previous,
};
left_shifted.write_to_storage(storage).await
}
pub(crate) async fn get_from_storage<S: Database + Send + Sync>(
storage: &StorageManager<S>,
key: &NodeKey,
target_epoch: u64,
) -> Result<TreeNode, StorageError> {
TreeNodeWithPreviousValue::get_appropriate_tree_node_from_storage(
storage,
key,
target_epoch,
)
.await
}
pub(crate) async fn batch_get_from_storage<S: Database + Send + Sync>(
storage: &StorageManager<S>,
keys: &[NodeKey],
target_epoch: u64,
) -> Result<Vec<TreeNode>, StorageError> {
TreeNodeWithPreviousValue::batch_get_appropriate_tree_node_from_storage(
storage,
keys,
target_epoch,
)
.await
}
}
#[derive(Clone, PartialEq, Eq, Hash, std::fmt::Debug)]
#[cfg_attr(
feature = "serde_serialization",
derive(serde::Deserialize, serde::Serialize)
)]
pub struct NodeKey(pub NodeLabel);
unsafe impl Sync for TreeNode {}
impl Clone for TreeNode {
fn clone(&self) -> Self {
Self {
label: self.label,
last_epoch: self.last_epoch,
least_descendant_ep: self.least_descendant_ep,
parent: self.parent,
node_type: self.node_type,
left_child: self.left_child,
right_child: self.right_child,
hash: self.hash,
}
}
}
impl TreeNode {
#[allow(clippy::too_many_arguments)]
async fn new<S: Database + Send + Sync>(
storage: &StorageManager<S>,
label: NodeLabel,
parent: NodeLabel,
node_type: NodeType,
birth_epoch: u64,
least_descendant_ep: u64,
left_child: Option<NodeLabel>,
right_child: Option<NodeLabel>,
hash: [u8; 32],
) -> Result<Self, StorageError> {
let new_node = TreeNode {
label,
last_epoch: birth_epoch,
least_descendant_ep,
parent, node_type,
left_child,
right_child,
hash,
};
new_node.write_to_storage_impl(storage, true).await?;
Ok(new_node)
}
#[cfg(test)]
pub(crate) async fn insert_single_leaf_and_hash<S: Database + Sync + Send, H: Hasher>(
&mut self,
storage: &StorageManager<S>,
new_leaf: Self,
epoch: u64,
num_nodes: &mut u64,
include_ep: Option<bool>,
) -> Result<(), AkdError> {
self.insert_single_leaf_helper::<_, H>(
storage, new_leaf, epoch, num_nodes, true, include_ep,
)
.await
}
pub(crate) async fn insert_leaf<S: Database + Sync + Send, H: Hasher>(
&mut self,
storage: &StorageManager<S>,
new_leaf: Self,
epoch: u64,
num_nodes: &mut u64,
include_ep: Option<bool>,
) -> Result<(), AkdError> {
self.insert_single_leaf_helper::<_, H>(
storage, new_leaf, epoch, num_nodes, false, include_ep,
)
.await
}
#[async_recursion]
pub(crate) async fn insert_single_leaf_helper<S: Database + Sync + Send, H: Hasher>(
&mut self,
storage: &StorageManager<S>,
new_leaf: Self,
epoch: u64,
num_nodes: &mut u64,
hashing: bool,
exclude_ep: Option<bool>,
) -> Result<(), AkdError> {
let (lcs_label, dir_leaf, dir_self) = self
.label
.get_longest_common_prefix_and_dirs(new_leaf.label);
if self.is_root() {
*num_nodes += 1;
let child_state = self.get_child_state(storage, dir_leaf, epoch).await?;
if child_state.is_none() {
return self
.insert_single_leaf_helper_root_handler::<S, H>(
storage, new_leaf, epoch, hashing, exclude_ep, dir_leaf,
)
.await;
}
}
match dir_self {
Some(_) => {
self.insert_single_leaf_helper_base_case_handler::<S, H>(
storage, new_leaf, epoch, num_nodes, hashing, exclude_ep, lcs_label, dir_leaf,
dir_self,
)
.await
}
None => {
self.insert_single_leaf_helper_recursive_case_handler::<S, H>(
storage, new_leaf, epoch, num_nodes, hashing, exclude_ep, dir_leaf,
)
.await
}
}
}
pub(crate) async fn insert_single_leaf_helper_root_handler<
S: Database + Sync + Send,
H: Hasher,
>(
&mut self,
storage: &StorageManager<S>,
mut new_leaf: Self,
epoch: u64,
hashing: bool,
exclude_ep: Option<bool>,
dir_leaf: Option<usize>,
) -> Result<(), AkdError> {
self.set_child(storage, &mut (dir_leaf, &mut new_leaf), epoch)
.await?;
if hashing {
new_leaf
.update_node_hash::<_, H>(storage, epoch, exclude_ep)
.await?;
self.update_node_hash::<_, H>(storage, epoch, exclude_ep)
.await?;
} else {
new_leaf.write_to_storage(storage).await?;
self.write_to_storage(storage).await?;
}
Ok(())
}
#[async_recursion]
#[allow(clippy::too_many_arguments)]
pub(crate) async fn insert_single_leaf_helper_base_case_handler<
S: Database + Sync + Send,
H: Hasher,
>(
&mut self,
storage: &StorageManager<S>,
mut new_leaf: Self,
epoch: u64,
num_nodes: &mut u64,
hashing: bool,
exclude_ep: Option<bool>,
lcs_label: NodeLabel,
dir_leaf: Option<usize>,
dir_self: Option<usize>,
) -> Result<(), AkdError> {
*num_nodes += 1;
let mut parent = TreeNode::get_from_storage(storage, &NodeKey(self.parent), epoch).await?;
let self_dir_in_parent = parent.get_direction(self);
debug!("BEGIN create new node");
let mut new_node = TreeNode::new(
storage,
lcs_label,
parent.label,
NodeType::Interior,
epoch,
min(self.least_descendant_ep, epoch),
None,
None,
[0u8; 32],
)
.await?;
debug!("BEGIN set node child parent(new_node)");
parent
.set_child(storage, &mut (self_dir_in_parent, &mut new_node), epoch)
.await?;
debug!("BEGIN set node child new_node(new_leaf)");
new_node
.set_child(storage, &mut (dir_leaf, &mut new_leaf), epoch)
.await?;
debug!("BEGIN set node child new_node(self)");
new_node
.set_child(storage, &mut (dir_self, self), epoch)
.await?;
if hashing {
debug!("BEGIN update hashes");
new_leaf
.update_node_hash::<_, H>(storage, epoch, exclude_ep)
.await?;
new_node
.update_node_hash::<_, H>(storage, epoch, exclude_ep)
.await?;
parent
.update_node_hash::<_, H>(storage, epoch, exclude_ep)
.await?;
} else {
new_node.write_to_storage(storage).await?;
parent.write_to_storage(storage).await?;
}
debug!("END insert single leaf (dir_self = Some)");
Ok(())
}
#[allow(clippy::too_many_arguments)]
#[async_recursion]
pub(crate) async fn insert_single_leaf_helper_recursive_case_handler<
S: Database + Sync + Send,
H: Hasher,
>(
&mut self,
storage: &StorageManager<S>,
new_leaf: Self,
epoch: u64,
num_nodes: &mut u64,
hashing: bool,
exclude_ep: Option<bool>,
dir_leaf: Option<usize>,
) -> Result<(), AkdError> {
debug!("BEGIN get child node from storage");
let child_node = self.get_child_state(storage, dir_leaf, epoch).await?;
debug!("BEGIN insert single leaf helper");
match child_node {
Some(mut child_node) => {
child_node
.insert_single_leaf_helper::<_, H>(
storage, new_leaf, epoch, num_nodes, hashing, exclude_ep,
)
.await?;
if hashing {
debug!("BEGIN update hashes");
*self =
TreeNode::get_from_storage(storage, &NodeKey(self.label), epoch).await?;
if self.node_type != NodeType::Leaf {
self.update_node_hash::<_, H>(storage, epoch, exclude_ep)
.await?;
}
} else {
debug!("BEGIN retrieve self");
*self =
TreeNode::get_from_storage(storage, &NodeKey(self.label), epoch).await?;
}
debug!("END insert single leaf (dir_self = None)");
Ok(())
}
None => Err(AkdError::TreeNode(TreeNodeError::NoChildAtEpoch(
epoch,
dir_leaf.unwrap(),
))),
}
}
pub(crate) async fn update_node_hash<S: Database + Sync + Send, H: Hasher>(
&mut self,
storage: &StorageManager<S>,
epoch: u64,
exclude_ep: Option<bool>,
) -> Result<(), AkdError> {
self.last_epoch = epoch;
let exclude_ep_val = exclude_ep.unwrap_or(false);
match self.node_type {
NodeType::Leaf => {
}
_ => {
let left_child_state = self.get_child_state(storage, Some(0), epoch).await?;
let right_child_state = self.get_child_state(storage, Some(1), epoch).await?;
let child_hashes = H::merge(&[
optional_child_state_label_hash::<H>(&left_child_state, exclude_ep_val)?,
optional_child_state_label_hash::<H>(&right_child_state, exclude_ep_val)?,
]);
self.hash = from_digest::<H>(child_hashes);
}
}
self.write_to_storage(storage).await?;
Ok(())
}
pub(crate) async fn set_child<S: Database + Sync + Send>(
&mut self,
storage: &StorageManager<S>,
child: &mut InsertionNode<'_>,
epoch: u64,
) -> Result<(), StorageError> {
let (direction, child_node) = child;
if let Some(direction) = direction {
if *direction == 0_usize {
self.left_child = Some(child_node.label);
}
if *direction == 1_usize {
self.right_child = Some(child_node.label);
}
} else {
return Err(StorageError::Other(format!(
"Unexpected child index: {:?}",
direction
)));
}
child_node.parent = self.label;
self.last_epoch = epoch;
if self.least_descendant_ep == 0u64 {
self.least_descendant_ep = child_node.least_descendant_ep;
} else {
self.least_descendant_ep =
min(self.least_descendant_ep, child_node.least_descendant_ep);
}
self.write_to_storage(storage).await?;
child_node.write_to_storage(storage).await?;
Ok(())
}
pub(crate) fn get_child_label(&self, dir: Direction) -> Option<NodeLabel> {
if dir == Some(0) {
self.left_child
} else if dir == Some(1) {
self.right_child
} else {
None
}
}
fn get_direction(&self, node: &Self) -> Direction {
if let Some(label) = self.left_child {
if label == node.label {
return Some(0);
}
}
if let Some(label) = self.right_child {
if label == node.label {
return Some(1);
}
}
None
}
pub(crate) fn is_root(&self) -> bool {
matches!(self.node_type, NodeType::Root)
}
pub(crate) fn is_leaf(&self) -> bool {
matches!(self.node_type, NodeType::Leaf)
}
pub(crate) async fn get_child_state<S: Database + Sync + Send>(
&self,
storage: &StorageManager<S>,
direction: Direction,
current_epoch: u64,
) -> Result<Option<TreeNode>, AkdError> {
match direction {
Direction::None => Err(AkdError::TreeNode(TreeNodeError::NoDirection(
self.label, None,
))),
Direction::Some(_dir) => {
if let Some(child_label) = self.get_child_label(direction) {
let child_key = NodeKey(child_label);
let get_result =
Self::get_from_storage(storage, &child_key, current_epoch).await;
match get_result {
Ok(node) => Ok(Some(node)),
Err(StorageError::NotFound(_)) => Ok(None),
_ => Err(AkdError::Storage(StorageError::NotFound(format!(
"TreeNode {:?}",
child_key
)))),
}
} else {
Ok(None)
}
}
}
}
pub(crate) fn get_child(&self, direction: Direction) -> Result<Option<NodeLabel>, AkdError> {
match direction {
Direction::None => Err(AkdError::TreeNode(TreeNodeError::NoDirection(
self.label, None,
))),
Direction::Some(dir) => {
if dir == 0 {
Ok(self.left_child)
} else if dir == 1 {
Ok(self.right_child)
} else {
Err(AkdError::TreeNode(TreeNodeError::InvalidDirection(dir)))
}
}
}
}
pub(crate) fn get_latest_epoch(&self) -> u64 {
self.last_epoch
}
#[allow(unused)]
pub(crate) fn get_least_descendant_epoch(&self) -> u64 {
self.least_descendant_ep
}
}
pub(crate) fn hash_u8_with_label<H: Hasher>(
digest: &[u8],
label: NodeLabel,
) -> Result<H::Digest, AkdError> {
Ok(H::merge(&[to_digest::<H>(digest)?, hash_label::<H>(label)]))
}
pub(crate) fn optional_child_state_to_label(input: &Option<TreeNode>) -> NodeLabel {
match input {
Some(child_state) => child_state.label,
None => EMPTY_LABEL,
}
}
pub(crate) fn optional_child_state_label_hash<H: Hasher>(
input: &Option<TreeNode>,
exclude_ep_val: bool,
) -> Result<H::Digest, AkdError> {
match input {
Some(child_state) => {
let mut hash = to_digest::<H>(&child_state.hash)?;
if child_state.is_leaf() && !exclude_ep_val {
hash = H::merge_with_int(hash, child_state.last_epoch);
}
Ok(H::merge(&[hash, hash_label::<H>(child_state.label)]))
}
None => Ok(H::merge(&[
crate::utils::empty_node_hash::<H>(),
hash_label::<H>(EMPTY_LABEL),
])),
}
}
pub(crate) fn optional_child_state_hash<H: Hasher>(
input: &Option<TreeNode>,
) -> Result<H::Digest, AkdError> {
match input {
Some(child_state) => {
if child_state.is_leaf() {
Ok(H::merge_with_int(
to_digest::<H>(&child_state.hash)?,
child_state.last_epoch,
))
} else {
to_digest::<H>(&child_state.hash)
}
}
None => Ok(crate::utils::empty_node_hash::<H>()),
}
}
pub async fn create_empty_root<H: Hasher, S: Database + Sync + Send>(
storage: &StorageManager<S>,
ep: Option<u64>,
least_descendant_ep: Option<u64>,
) -> Result<TreeNode, StorageError> {
let empty_root_hash = from_digest::<H>(crate::utils::empty_node_hash_no_label::<H>());
let mut node = TreeNode::new(
storage,
NodeLabel::root(),
NodeLabel::root(),
NodeType::Root,
0u64,
0u64,
None,
None,
empty_root_hash,
)
.await?;
if let Some(epoch) = ep {
node.last_epoch = epoch;
}
if let Some(least_ep) = least_descendant_ep {
node.least_descendant_ep = least_ep;
}
Ok(node)
}
pub async fn create_leaf_node<H: Hasher, S: Database + Sync + Send>(
storage: &StorageManager<S>,
label: NodeLabel,
value: &H::Digest,
parent: NodeLabel,
birth_epoch: u64,
) -> Result<TreeNode, StorageError> {
let new_node = TreeNode::new(
storage,
label,
parent,
NodeType::Leaf,
birth_epoch,
birth_epoch,
None,
None,
from_digest::<H>(*value),
)
.await?;
Ok(new_node)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
node_label::{byte_arr_from_u64, hash_label, NodeLabel},
EMPTY_VALUE,
};
use std::convert::TryInto;
use winter_crypto::{hashers::Blake3_256, Hasher};
use winter_math::fields::f128::BaseElement;
type Blake3 = Blake3_256<BaseElement>;
type InMemoryDb = crate::storage::memory::AsyncInMemoryDatabase;
use crate::storage::manager::StorageManager;
#[tokio::test]
async fn test_least_descendant_ep() -> Result<(), AkdError> {
let database = InMemoryDb::new();
let db = StorageManager::new_no_cache(&database);
let mut root =
create_empty_root::<Blake3, InMemoryDb>(&db, Option::Some(0u64), Option::Some(0u64))
.await?;
let new_leaf = create_leaf_node::<Blake3, InMemoryDb>(
&db,
NodeLabel::new(byte_arr_from_u64(0b00u64), 2u32),
&Blake3::hash(&EMPTY_VALUE),
NodeLabel::root(),
1,
)
.await?;
let leaf_1 = create_leaf_node::<Blake3, InMemoryDb>(
&db,
NodeLabel::new(byte_arr_from_u64(0b11u64 << 62), 2u32),
&Blake3::hash(&[1u8]),
NodeLabel::root(),
2,
)
.await?;
let leaf_2 = create_leaf_node::<Blake3, InMemoryDb>(
&db,
NodeLabel::new(byte_arr_from_u64(0b10u64 << 62), 2u32),
&Blake3::hash(&[1u8, 1u8]),
NodeLabel::root(),
3,
)
.await?;
root.write_to_storage(&db).await?;
let mut num_nodes = 1;
root.insert_single_leaf_and_hash::<_, Blake3>(
&db,
new_leaf.clone(),
1,
&mut num_nodes,
None,
)
.await?;
root.insert_single_leaf_and_hash::<_, Blake3>(&db, leaf_1.clone(), 2, &mut num_nodes, None)
.await?;
root.insert_single_leaf_and_hash::<_, Blake3>(&db, leaf_2.clone(), 3, &mut num_nodes, None)
.await?;
let stored_root = db
.get::<TreeNodeWithPreviousValue>(&NodeKey(NodeLabel::root()))
.await?;
let root_least_descendent_ep = match stored_root {
DbRecord::TreeNode(node) => node.latest_node.least_descendant_ep,
_ => panic!("Root not found in storage."),
};
let stored_right_child = db
.get::<TreeNodeWithPreviousValue>(&NodeKey(root.right_child.unwrap()))
.await?;
let right_child_least_descendent_ep = match stored_right_child {
DbRecord::TreeNode(node) => node.latest_node.least_descendant_ep,
_ => panic!("Root not found in storage."),
};
let stored_left_child = db
.get::<TreeNodeWithPreviousValue>(&NodeKey(root.left_child.unwrap()))
.await?;
let left_child_least_descendent_ep = match stored_left_child {
DbRecord::TreeNode(node) => node.latest_node.least_descendant_ep,
_ => panic!("Root not found in storage."),
};
let root_expected_least_dec = 1u64;
assert!(
root_expected_least_dec == root_least_descendent_ep,
"Least decendent epoch not equal to expected: root, expected: {:?}, got: {:?}",
root_expected_least_dec,
root_least_descendent_ep
);
let right_child_expected_least_dec = 2u64;
assert!(
right_child_expected_least_dec == right_child_least_descendent_ep,
"Least decendent epoch not equal to expected: right child"
);
let left_child_expected_least_dec = 1u64;
assert!(
left_child_expected_least_dec == left_child_least_descendent_ep,
"Least decendent epoch not equal to expected: left child"
);
Ok(())
}
#[tokio::test]
async fn test_insert_single_leaf_root() -> Result<(), AkdError> {
let database = InMemoryDb::new();
let db = StorageManager::new_no_cache(&database);
let mut root =
create_empty_root::<Blake3, InMemoryDb>(&db, Option::Some(0u64), Option::Some(0u64))
.await?;
root.write_to_storage(&db).await?;
let mut num_nodes = 1;
let leaf_0 = create_leaf_node::<Blake3, InMemoryDb>(
&db,
NodeLabel::new(byte_arr_from_u64(0b0u64), 1u32),
&Blake3::hash(&EMPTY_VALUE),
NodeLabel::root(),
0,
)
.await?;
root.insert_single_leaf_and_hash::<_, Blake3>(&db, leaf_0.clone(), 0, &mut num_nodes, None)
.await?;
assert_eq!(num_nodes, 2);
let leaf_1 = create_leaf_node::<Blake3, InMemoryDb>(
&db,
NodeLabel::new(byte_arr_from_u64(0b1u64 << 63), 1u32),
&Blake3::hash(&[1u8]),
NodeLabel::root(),
0,
)
.await?;
root.insert_single_leaf_and_hash::<_, Blake3>(&db, leaf_1.clone(), 0, &mut num_nodes, None)
.await?;
let leaf_0_hash = Blake3::merge(&[
Blake3::merge_with_int(Blake3::hash(&EMPTY_VALUE), 0),
hash_label::<Blake3>(leaf_0.label),
]);
let leaf_1_hash = Blake3::merge(&[
Blake3::merge_with_int(Blake3::hash(&[1u8]), 0),
hash_label::<Blake3>(leaf_1.label),
]);
let leaves_hash = Blake3::merge(&[leaf_0_hash, leaf_1_hash]);
let expected = Blake3::merge(&[leaves_hash, hash_label::<Blake3>(root.label)]);
let stored_root = db
.get::<TreeNodeWithPreviousValue>(&NodeKey(NodeLabel::root()))
.await?;
let root_digest = match stored_root {
DbRecord::TreeNode(node) => {
hash_u8_with_label::<Blake3>(&node.latest_node.hash, node.label)?
}
_ => panic!("Root not found in storage."),
};
assert_eq!(root_digest, expected, "Root hash not equal to expected");
Ok(())
}
#[tokio::test]
async fn test_insert_single_leaf_below_root() -> Result<(), AkdError> {
let database = InMemoryDb::new();
let db = StorageManager::new_no_cache(&database);
let mut root =
create_empty_root::<Blake3, InMemoryDb>(&db, Option::Some(0u64), Option::Some(0u64))
.await?;
let leaf_0 = create_leaf_node::<Blake3, InMemoryDb>(
&db,
NodeLabel::new(byte_arr_from_u64(0b00u64), 2u32),
&Blake3::hash(&EMPTY_VALUE),
NodeLabel::root(),
1,
)
.await?;
let leaf_1 = create_leaf_node::<Blake3, InMemoryDb>(
&db,
NodeLabel::new(byte_arr_from_u64(0b11u64 << 62), 2u32),
&Blake3::hash(&[1u8]),
NodeLabel::root(),
2,
)
.await?;
let leaf_2 = create_leaf_node::<Blake3, InMemoryDb>(
&db,
NodeLabel::new(byte_arr_from_u64(0b10u64 << 62), 2u32),
&Blake3::hash(&[1u8, 1u8]),
NodeLabel::root(),
3,
)
.await?;
let leaf_0_hash = Blake3::merge(&[
Blake3::merge_with_int(Blake3::hash(&EMPTY_VALUE), 1),
hash_label::<Blake3>(leaf_0.label),
]);
let leaf_1_hash = Blake3::merge(&[
Blake3::merge_with_int(Blake3::hash(&[0b1u8]), 2),
hash_label::<Blake3>(leaf_1.label),
]);
let leaf_2_hash = Blake3::merge(&[
Blake3::merge_with_int(Blake3::hash(&[1u8, 1u8]), 3),
hash_label::<Blake3>(leaf_2.label),
]);
let right_child_expected_hash = Blake3::merge(&[
Blake3::merge(&[leaf_2_hash, leaf_1_hash]),
hash_label::<Blake3>(NodeLabel::new(byte_arr_from_u64(0b1u64 << 63), 1u32)),
]);
root.write_to_storage(&db).await?;
let mut num_nodes = 1;
root.insert_single_leaf_and_hash::<_, Blake3>(&db, leaf_0.clone(), 1, &mut num_nodes, None)
.await?;
root.insert_single_leaf_and_hash::<_, Blake3>(&db, leaf_1.clone(), 2, &mut num_nodes, None)
.await?;
root.insert_single_leaf_and_hash::<_, Blake3>(&db, leaf_2.clone(), 3, &mut num_nodes, None)
.await?;
let stored_root = db
.get::<TreeNodeWithPreviousValue>(&NodeKey(NodeLabel::root()))
.await?;
let root_digest = match stored_root {
DbRecord::TreeNode(node) => {
hash_u8_with_label::<Blake3>(&node.latest_node.hash, node.label)?
}
_ => panic!("Root not found in storage."),
};
let expected = Blake3::merge(&[
Blake3::merge(&[leaf_0_hash, right_child_expected_hash]),
hash_label::<Blake3>(root.label),
]);
assert!(root_digest == expected, "Root hash not equal to expected");
Ok(())
}
#[tokio::test]
async fn test_insert_single_leaf_below_root_both_sides() -> Result<(), AkdError> {
let database = InMemoryDb::new();
let db = StorageManager::new_no_cache(&database);
let mut root =
create_empty_root::<Blake3, InMemoryDb>(&db, Option::Some(0u64), Option::Some(0u64))
.await?;
let leaf_0 = create_leaf_node::<Blake3, InMemoryDb>(
&db,
NodeLabel::new(byte_arr_from_u64(0b000u64), 3u32),
&Blake3::hash(&EMPTY_VALUE),
NodeLabel::root(),
0,
)
.await?;
let leaf_1 = create_leaf_node::<Blake3, InMemoryDb>(
&db,
NodeLabel::new(byte_arr_from_u64(0b111u64 << 61), 3u32),
&Blake3::hash(&[1u8]),
NodeLabel::root(),
0,
)
.await?;
let leaf_2 = create_leaf_node::<Blake3, InMemoryDb>(
&db,
NodeLabel::new(byte_arr_from_u64(0b100u64 << 61), 3u32),
&Blake3::hash(&[1u8, 1u8]),
NodeLabel::root(),
0,
)
.await?;
let leaf_3 = create_leaf_node::<Blake3, InMemoryDb>(
&db,
NodeLabel::new(byte_arr_from_u64(0b010u64 << 61), 3u32),
&Blake3::hash(&[0u8, 1u8]),
NodeLabel::root(),
0,
)
.await?;
let leaf_0_hash = Blake3::merge(&[
Blake3::merge_with_int(Blake3::hash(&EMPTY_VALUE), 1),
hash_label::<Blake3>(leaf_0.label),
]);
let leaf_1_hash = Blake3::merge(&[
Blake3::merge_with_int(Blake3::hash(&[1u8]), 2),
hash_label::<Blake3>(leaf_1.label),
]);
let leaf_2_hash = Blake3::merge(&[
Blake3::merge_with_int(Blake3::hash(&[1u8, 1u8]), 3),
hash_label::<Blake3>(leaf_2.label),
]);
let leaf_3_hash = Blake3::merge(&[
Blake3::merge_with_int(Blake3::hash(&[0u8, 1u8]), 4),
hash_label::<Blake3>(leaf_3.label),
]);
let right_child_expected_hash = Blake3::merge(&[
Blake3::merge(&[leaf_2_hash, leaf_1_hash]),
hash_label::<Blake3>(NodeLabel::new(byte_arr_from_u64(0b1u64 << 63), 1u32)),
]);
let left_child_expected_hash = Blake3::merge(&[
Blake3::merge(&[leaf_0_hash, leaf_3_hash]),
hash_label::<Blake3>(NodeLabel::new(byte_arr_from_u64(0b0u64), 1u32)),
]);
root.write_to_storage(&db).await?;
let mut num_nodes = 1;
root.insert_single_leaf_and_hash::<_, Blake3>(&db, leaf_0.clone(), 1, &mut num_nodes, None)
.await?;
root.insert_single_leaf_and_hash::<_, Blake3>(&db, leaf_1.clone(), 2, &mut num_nodes, None)
.await?;
root.insert_single_leaf_and_hash::<_, Blake3>(&db, leaf_2.clone(), 3, &mut num_nodes, None)
.await?;
root.insert_single_leaf_and_hash::<_, Blake3>(&db, leaf_3.clone(), 4, &mut num_nodes, None)
.await?;
let stored_root = db
.get::<TreeNodeWithPreviousValue>(&NodeKey(NodeLabel::root()))
.await?;
let root_digest = match stored_root {
DbRecord::TreeNode(node) => {
hash_u8_with_label::<Blake3>(&node.latest_node.hash, node.label)?
}
_ => panic!("Root not found in storage."),
};
let expected = Blake3::merge(&[
Blake3::merge(&[left_child_expected_hash, right_child_expected_hash]),
hash_label::<Blake3>(root.label),
]);
assert!(root_digest == expected, "Root hash not equal to expected");
Ok(())
}
#[tokio::test]
async fn test_insert_single_leaf_full_tree() -> Result<(), AkdError> {
let database = InMemoryDb::new();
let db = StorageManager::new_no_cache(&database);
let mut root =
create_empty_root::<Blake3, InMemoryDb>(&db, Option::Some(0u64), Option::Some(0u64))
.await?;
root.write_to_storage(&db).await?;
let mut num_nodes = 1;
let mut leaves = Vec::<TreeNode>::new();
let mut leaf_hashes = Vec::new();
for i in 0u64..8u64 {
let leaf_u64 = i << 61;
let new_leaf = create_leaf_node::<Blake3, InMemoryDb>(
&db,
NodeLabel::new(byte_arr_from_u64(leaf_u64), 3u32),
&Blake3::hash(&leaf_u64.to_be_bytes()),
NodeLabel::root(),
7 - i,
)
.await?;
leaf_hashes.push(Blake3::merge(&[
Blake3::merge_with_int(Blake3::hash(&leaf_u64.to_be_bytes()), 8 - i),
hash_label::<Blake3>(new_leaf.label),
]));
leaves.push(new_leaf);
}
let mut layer_1_hashes = Vec::new();
let mut j = 0u64;
for i in 0..4 {
let left_child_hash = leaf_hashes[2 * i];
let right_child_hash = leaf_hashes[2 * i + 1];
layer_1_hashes.push(Blake3::merge(&[
Blake3::merge(&[left_child_hash, right_child_hash]),
hash_label::<Blake3>(NodeLabel::new(byte_arr_from_u64(j << 62), 2u32)),
]));
j += 1;
}
let mut layer_2_hashes = Vec::new();
let mut j = 0u64;
for i in 0..2 {
let left_child_hash = layer_1_hashes[2 * i];
let right_child_hash = layer_1_hashes[2 * i + 1];
layer_2_hashes.push(Blake3::merge(&[
Blake3::merge(&[left_child_hash, right_child_hash]),
hash_label::<Blake3>(NodeLabel::new(byte_arr_from_u64(j << 63), 1u32)),
]));
j += 1;
}
let expected = Blake3::merge(&[
Blake3::merge(&[layer_2_hashes[0], layer_2_hashes[1]]),
hash_label::<Blake3>(root.label),
]);
for i in 0..8 {
let ep: u64 = i.try_into().unwrap();
root.insert_single_leaf_and_hash::<_, Blake3>(
&db,
leaves[7 - i].clone(),
ep + 1,
&mut num_nodes,
None,
)
.await?;
}
let stored_root = db
.get::<TreeNodeWithPreviousValue>(&NodeKey(NodeLabel::root()))
.await?;
let root_digest = match stored_root {
DbRecord::TreeNode(node) => {
hash_u8_with_label::<Blake3>(&node.latest_node.hash, node.label)?
}
_ => panic!("Root not found in storage."),
};
assert!(root_digest == expected, "Root hash not equal to expected");
Ok(())
}
}