use core::iter;
use super::jellyfish::JellyfishMerkleTree;
use super::jellyfish::TreeUpdateBatch;
use super::tree_store::*;
use super::types::*;
use radix_common::crypto::Hash;
use radix_rust::prelude::*;
use radix_rust::rust::ops::Deref;
use radix_substate_store_interface::interface::DbNodeKey;
pub(crate) type DbEntityKey = DbNodeKey;
pub const TIER_SEPARATOR: u8 = b'_';
pub trait StoredNode {
type Payload;
#[allow(clippy::wrong_self_convention)]
fn into_jmt_node(&self, key: &TreeNodeKey) -> Node<Self::Payload>;
fn from_jmt_node(node: &Node<Self::Payload>, key: &TreeNodeKey) -> Self;
}
pub trait StateTreeTier {
type TypedLeafKey;
type StoredNode: StoredNode<Payload = Self::Payload>;
type Payload: Clone;
fn to_leaf_key(typed_key: &Self::TypedLeafKey) -> LeafKey;
fn to_typed_key(leaf_key: LeafKey) -> Self::TypedLeafKey;
fn root_version(&self) -> Option<Version>;
}
pub trait ReadableTier: StateTreeTier {
fn get_local_node(&self, local_key: &TreeNodeKey) -> Option<Self::StoredNode>;
fn jmt(&self) -> JellyfishMerkleTree<'_, Self, Self::Payload> {
JellyfishMerkleTree::new(self)
}
fn get_persisted_leaf_payload(&self, key: &Self::TypedLeafKey) -> Option<Self::Payload> {
let root_version = self.root_version()?;
let leaf_key = Self::to_leaf_key(key);
let (leaf_node_data, _proof) = self.jmt().get_with_proof(&leaf_key, root_version).unwrap();
leaf_node_data.map(|(_hash, payload, _version)| payload)
}
}
pub struct TierLeaf<T: StateTreeTier> {
pub key: T::TypedLeafKey,
pub value_hash: Hash,
pub payload: T::Payload,
pub local_key: TreeNodeKey,
}
impl<T: StateTreeTier<Payload = Version>> TierLeaf<T> {
pub fn new(local_key: TreeNodeKey, leaf: TreeLeafNode) -> Self {
let TreeLeafNode {
key_suffix,
value_hash,
last_hash_change_version,
} = leaf;
let full_key = NibblePath::from_iter(
local_key
.nibble_path()
.nibbles()
.chain(key_suffix.nibbles()),
);
Self {
key: T::to_typed_key(LeafKey::new(full_key.bytes())),
value_hash,
payload: last_hash_change_version,
local_key,
}
}
}
pub fn iter_leaves_from<'t, T>(
tier: impl Deref<Target = T> + Clone + 't,
from_key: Option<&T::TypedLeafKey>,
) -> Box<dyn Iterator<Item = TierLeaf<T>> + 't>
where
T: ReadableTier<StoredNode = TreeNode, Payload = Version> + 't,
T::TypedLeafKey: 't,
{
tier.root_version()
.map(|version| {
recurse_until_leaves(
tier,
TreeNodeKey::new_empty_path(version),
from_key
.map(|from| T::to_leaf_key(from).into_path().nibbles().collect())
.unwrap_or_else(VecDeque::new),
)
})
.unwrap_or_else(|| Box::new(iter::empty()))
}
pub fn recurse_until_leaves<'t, T>(
tier: impl Deref<Target = T> + Clone + 't,
at_key: TreeNodeKey,
from_nibbles: VecDeque<Nibble>,
) -> Box<dyn Iterator<Item = TierLeaf<T>> + 't>
where
T: ReadableTier<StoredNode = TreeNode, Payload = Version> + 't,
T::TypedLeafKey: 't,
{
let Some(node) = tier.get_local_node(&at_key) else {
panic!("{:?} referenced but not found in the storage", at_key);
};
match node {
TreeNode::Internal(internal) => {
let mut child_from_nibbles = from_nibbles;
let from_nibble = child_from_nibbles.pop_front();
Box::new(
internal
.children
.into_iter()
.filter(move |child| Some(child.nibble) >= from_nibble)
.flat_map(move |child| {
let child_key = at_key.gen_child_node_key(child.version, child.nibble);
let child_from_nibbles = if Some(child.nibble) == from_nibble {
mem::take(&mut child_from_nibbles)
} else {
VecDeque::new()
};
recurse_until_leaves(tier.clone(), child_key, child_from_nibbles)
}),
)
}
TreeNode::Leaf(leaf) => Box::new(
Some(leaf)
.filter(move |leaf| leaf.key_suffix.nibbles().ge(from_nibbles))
.map(|leaf| TierLeaf::new(at_key, leaf))
.into_iter(),
),
TreeNode::Null => Box::new(iter::empty()),
}
}
impl<R: ReadableTier + ?Sized> TreeReader<<R::StoredNode as StoredNode>::Payload> for R {
fn get_node_option(
&self,
node_key: &TreeNodeKey,
) -> Result<Option<Node<<R::StoredNode as StoredNode>::Payload>>, StorageError> {
Ok(self
.get_local_node(node_key)
.map(|tree_node| tree_node.into_jmt_node(node_key)))
}
}
pub trait WriteableTier: StateTreeTier {
fn insert_local_node(&self, local_key: &TreeNodeKey, node: Self::StoredNode);
fn record_stale_local_node(&self, local_key: &TreeNodeKey);
fn set_root_version(&mut self, new_version: Option<Version>);
}
pub struct TierUpdateBatch<P> {
pub new_version: Version,
pub new_root_hash: Option<Hash>,
pub tree_update_batch: TreeUpdateBatch<P>,
}
pub trait RwTier: ReadableTier + WriteableTier {
fn generate_tier_update_batch<'a>(
&self,
new_version: Version,
leaf_updates: impl Iterator<Item = (&'a Self::TypedLeafKey, Option<(Hash, Self::Payload)>)>,
) -> TierUpdateBatch<Self::Payload>
where
<Self as StateTreeTier>::TypedLeafKey: 'a,
{
let value_set = leaf_updates
.map(|(key, option)| (Self::to_leaf_key(key), option))
.collect();
let (root_hash, update_batch) = self
.jmt()
.batch_put_value_set(value_set, None, self.root_version(), new_version)
.expect("error while reading tree during put");
let root_hash = if root_hash == SPARSE_MERKLE_PLACEHOLDER_HASH {
None
} else {
Some(root_hash)
};
TierUpdateBatch {
new_version,
tree_update_batch: update_batch,
new_root_hash: root_hash,
}
}
fn apply_tier_update_batch(&mut self, tier_update_batch: &TierUpdateBatch<Self::Payload>) {
let TierUpdateBatch {
new_version,
tree_update_batch: update_batch,
new_root_hash: _,
} = tier_update_batch;
for (key, node) in update_batch.node_batch.iter().flatten() {
self.insert_local_node(key, Self::StoredNode::from_jmt_node(node, key));
}
for stale_node in update_batch.stale_node_index_batch.iter().flatten() {
self.record_stale_local_node(&stale_node.node_key);
}
self.set_root_version(Some(*new_version));
}
}
impl<T: ReadableTier + WriteableTier> RwTier for T {}