penumbra_tct/internal/complete/
node.rsuse serde::{Deserialize, Serialize};
use crate::prelude::*;
use super::super::frontier;
pub mod children;
pub use children::Children;
#[derive(Clone, Debug)]
pub struct Node<Child: Clone> {
hash: Hash,
forgotten: [Forgotten; 4],
children: Children<Child>,
}
impl<Child: Serialize + Clone> Serialize for Node<Child> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.children.serialize(serializer)
}
}
impl<'de, Child: Height + GetHash + Deserialize<'de> + Clone> Deserialize<'de> for Node<Child> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let children = Children::deserialize(deserializer)?;
Ok(Self {
hash: children.hash(),
forgotten: Default::default(),
children,
})
}
}
impl<Child: Height + Clone> Node<Child> {
pub(in super::super) fn from_children_or_else_hash(
forgotten: [Forgotten; 4],
children: [Insert<Child>; 4],
) -> Insert<Self>
where
Child: GetHash,
{
match Children::try_from(children) {
Ok(children) => Insert::Keep(Self {
hash: children.hash(),
forgotten,
children,
}),
Err([a, b, c, d]) => {
Insert::Hash(Hash::node(<Self as Height>::Height::HEIGHT, a, b, c, d))
}
}
}
pub fn children(&self) -> [Insert<&Child>; 4] {
self.children.children()
}
pub fn forgotten(&self) -> [Forgotten; 4] {
self.forgotten
}
}
impl<Child: Height + Clone> Height for Node<Child> {
type Height = Succ<Child::Height>;
}
impl<Child: Complete + Clone> Complete for Node<Child>
where
Child::Focus: Clone,
{
type Focus = frontier::Node<Child::Focus>;
}
impl<Child: Height + GetHash + Clone> GetHash for Node<Child> {
#[inline]
fn hash(&self) -> Hash {
self.hash
}
#[inline]
fn cached_hash(&self) -> Option<Hash> {
Some(self.hash)
}
}
impl<Child: GetHash + Witness + Clone> Witness for Node<Child> {
#[inline]
fn witness(&self, index: impl Into<u64>) -> Option<(AuthPath<Self>, Hash)> {
let index = index.into();
let (which_way, index) = WhichWay::at(Self::Height::HEIGHT, index);
let (child, siblings) = which_way.pick(self.children());
let siblings = siblings.map(|sibling| sibling.hash());
let (child, leaf) = child.keep()?.witness(index)?;
Some((path::Node { siblings, child }, leaf))
}
}
impl<Child: GetHash + ForgetOwned + Clone> ForgetOwned for Node<Child> {
#[inline]
fn forget_owned(
self,
forgotten: Option<Forgotten>,
index: impl Into<u64>,
) -> (Insert<Self>, bool) {
let index = index.into();
let [a, b, c, d]: [Insert<Child>; 4] = self.children.into();
let (which_way, index) = WhichWay::at(Self::Height::HEIGHT, index);
let (children, was_forgotten) = match which_way {
WhichWay::Leftmost => {
let (a, forgotten) = match a {
Insert::Keep(a) => a.forget_owned(forgotten, index),
Insert::Hash(_) => (a, false),
};
([a, b, c, d], forgotten)
}
WhichWay::Left => {
let (b, forgotten) = match b {
Insert::Keep(b) => b.forget_owned(forgotten, index),
Insert::Hash(_) => (b, false),
};
([a, b, c, d], forgotten)
}
WhichWay::Right => {
let (c, forgotten) = match c {
Insert::Keep(c) => c.forget_owned(forgotten, index),
Insert::Hash(_) => (c, false),
};
([a, b, c, d], forgotten)
}
WhichWay::Rightmost => {
let (d, forgotten) = match d {
Insert::Keep(d) => d.forget_owned(forgotten, index),
Insert::Hash(_) => (d, false),
};
([a, b, c, d], forgotten)
}
};
let reconstructed = match Children::try_from(children) {
Ok(children) => {
let mut reconstructed = Self {
children,
hash: self.hash,
forgotten: self.forgotten,
};
if was_forgotten {
if let Some(forgotten) = forgotten {
reconstructed.forgotten[which_way] = forgotten.next();
}
}
Insert::Keep(reconstructed)
}
Err(_) => Insert::Hash(self.hash),
};
(reconstructed, was_forgotten)
}
}
impl<Child: Clone> GetPosition for Node<Child> {
fn position(&self) -> Option<u64> {
None
}
}
impl<'tree, Child: Height + structure::Any<'tree> + Clone> structure::Any<'tree> for Node<Child> {
fn kind(&self) -> Kind {
Kind::Internal {
height: <Self as Height>::Height::HEIGHT,
}
}
fn forgotten(&self) -> Forgotten {
self.forgotten.iter().copied().max().unwrap_or_default()
}
fn children(&'tree self) -> Vec<HashOrNode<'tree>> {
self.forgotten
.iter()
.copied()
.zip(self.children.children())
.map(|(forgotten, child)| match child {
Insert::Keep(node) => HashOrNode::Node(node),
Insert::Hash(hash) => HashOrNode::Hash(HashedNode {
hash,
forgotten,
height: <Child as Height>::Height::HEIGHT,
}),
})
.collect()
}
}
impl<Child: Height + OutOfOrderOwned + Clone> OutOfOrderOwned for Node<Child> {
fn uninitialized_out_of_order_insert_commitment_owned(
this: Insert<Self>,
index: u64,
commitment: StateCommitment,
) -> Self {
let (which_way, index) = WhichWay::at(<Self as Height>::Height::HEIGHT, index);
let (hash, forgotten, mut children) = match this {
Insert::Keep(Node {
hash,
forgotten,
children,
}) => (hash, forgotten, children.into()),
Insert::Hash(hash) => (hash, [Forgotten::default(); 4], {
let u = || Insert::Hash(Hash::uninitialized());
[u(), u(), u(), u()]
}),
};
let child = std::mem::replace(
&mut children[which_way],
Insert::Hash(Hash::uninitialized()),
);
children[which_way] = Insert::Keep(
Child::uninitialized_out_of_order_insert_commitment_owned(child, index, commitment),
);
let children = children.try_into().expect(
"adding a commitment to extant children always allows them to be reconstituted",
);
Node {
hash,
forgotten,
children,
}
}
}
impl<Child: GetHash + UncheckedSetHash + Clone> UncheckedSetHash for Node<Child> {
fn unchecked_set_hash(&mut self, index: u64, height: u8, hash: Hash) {
use std::cmp::Ordering::*;
match height.cmp(&Self::Height::HEIGHT) {
Greater => panic!("height too large when setting hash: {height}"),
Equal => self.hash = hash,
Less => {
let (which_way, index) = WhichWay::at(Self::Height::HEIGHT, index);
let (child, _) = which_way.pick(self.children.children_mut());
match child {
InsertMut::Keep(child) => child.unchecked_set_hash(index, height, hash),
InsertMut::Hash(child_hash) => {
if <Child as Height>::Height::HEIGHT == height {
*child_hash = hash
}
}
}
}
}
}
fn finish_initialize(&mut self) {
for child in self.children.children_mut() {
match child {
InsertMut::Keep(child) => child.finish_initialize(),
InsertMut::Hash(hash) => {
if hash.is_uninitialized() {
*hash = Hash::one();
}
}
}
}
if self.hash.is_uninitialized() {
self.hash = self.children.hash();
}
}
}
#[cfg(test)]
mod test {
#[test]
fn check_node_size() {
}
}