penumbra_tct/internal/frontier/
tier.rsuse std::fmt::Debug;
use serde::{Deserialize, Serialize};
use crate::prelude::*;
#[derive(Derivative, Serialize, Deserialize)]
#[derivative(
Debug(bound = "Item: Debug, Item::Complete: Debug"),
Clone(bound = "Item: Clone, Item::Complete: Clone")
)]
#[serde(bound(
serialize = "Item: Serialize, Item::Complete: Serialize",
deserialize = "Item: Deserialize<'de>, Item::Complete: Deserialize<'de>"
))]
pub struct Tier<Item: Focus + Clone>
where
Item::Complete: Clone,
{
inner: Inner<Item>,
}
type N<Focus> = frontier::Node<Focus>;
type L<Item> = frontier::Leaf<Item>;
pub type Nested<Item> = N<N<N<N<N<N<N<N<L<Item>>>>>>>>>;
#[derive(Derivative, Serialize, Deserialize)]
#[derivative(
Debug(bound = "Item: Debug, Item::Complete: Debug"),
Clone(bound = "Item: Clone, Item::Complete: Clone")
)]
#[serde(bound(
serialize = "Item: Serialize, Item::Complete: Serialize + Clone",
deserialize = "Item: Deserialize<'de>, Item::Complete: Deserialize<'de>"
))]
pub enum Inner<Item: Focus + Clone>
where
Item::Complete: Clone,
{
Frontier(Box<Nested<Item>>),
Complete(complete::Nested<Item::Complete>),
Hash(Hash),
}
impl<Item: Focus + Clone> From<Hash> for Tier<Item>
where
Item::Complete: Clone,
{
#[inline]
fn from(hash: Hash) -> Self {
Self {
inner: Inner::Hash(hash),
}
}
}
impl<Item: Focus + Clone> Tier<Item>
where
Item::Complete: Clone,
{
#[inline]
pub fn new(item: Item) -> Self {
Self {
inner: Inner::Frontier(Box::new(Nested::new(item))),
}
}
#[inline]
pub fn insert(&mut self, item: Item) -> Result<(), Item> {
let inner = std::mem::replace(&mut self.inner, Inner::Hash(Hash::zero()));
let result;
(result, *self) = match (Self { inner }.insert_owned(item)) {
Ok(this) => (Ok(()), this),
Err((item, this)) => (Err(item), this),
};
result
}
#[inline]
fn insert_owned(self, item: Item) -> Result<Self, (Item, Self)> {
match self.inner {
inner @ (Inner::Complete(_) | Inner::Hash(_)) => Err((item, Self { inner })),
Inner::Frontier(frontier) => {
if frontier.is_full() {
Err((
item,
Self {
inner: Inner::Frontier(frontier),
},
))
} else {
let inner =
Inner::Frontier(Box::new(frontier.insert_owned(item).unwrap_or_else(
|_| panic!("frontier is not full, so insert must succeed"),
)));
Ok(Self { inner })
}
}
}
}
#[inline]
pub fn update<T>(&mut self, f: impl FnOnce(&mut Item) -> T) -> Option<T> {
if let Inner::Frontier(frontier) = &mut self.inner {
frontier.update(f)
} else {
None
}
}
#[inline]
pub fn focus(&self) -> Option<&Item> {
if let Inner::Frontier(frontier) = &self.inner {
frontier.focus()
} else {
None
}
}
#[inline]
pub fn is_full(&self) -> bool {
match &self.inner {
Inner::Frontier(frontier) => frontier.is_full(),
Inner::Complete(_) | Inner::Hash(_) => true,
}
}
#[inline]
pub fn finalize(&mut self) -> bool {
let already_finalized = self.is_finalized();
let inner = std::mem::replace(&mut self.inner, Inner::Hash(Hash::zero()));
self.inner = match inner {
Inner::Frontier(frontier) => match frontier.finalize_owned() {
Insert::Hash(hash) => Inner::Hash(hash),
Insert::Keep(inner) => Inner::Complete(inner),
},
inner @ (Inner::Complete(_) | Inner::Hash(_)) => inner,
};
already_finalized
}
#[inline]
pub fn is_finalized(&self) -> bool {
match self.inner {
Inner::Frontier(_) => false,
Inner::Complete(_) | Inner::Hash(_) => true,
}
}
}
impl<Item: Focus + Clone> Height for Tier<Item>
where
Item::Complete: Clone,
{
type Height = <Nested<Item> as Height>::Height;
}
impl<Item: Focus + Clone> GetHash for Tier<Item>
where
Item::Complete: Clone,
{
#[inline]
fn hash(&self) -> Hash {
match &self.inner {
Inner::Frontier(frontier) => frontier.hash(),
Inner::Complete(complete) => complete.hash(),
Inner::Hash(hash) => *hash,
}
}
#[inline]
fn cached_hash(&self) -> Option<Hash> {
match &self.inner {
Inner::Frontier(frontier) => frontier.cached_hash(),
Inner::Complete(complete) => complete.cached_hash(),
Inner::Hash(hash) => Some(*hash),
}
}
}
impl<Item: Focus + Clone> Focus for Tier<Item>
where
Item::Complete: Clone,
{
type Complete = complete::Tier<Item::Complete>;
#[inline]
fn finalize_owned(self) -> Insert<Self::Complete> {
match self.inner {
Inner::Frontier(frontier) => match frontier.finalize_owned() {
Insert::Hash(hash) => Insert::Hash(hash),
Insert::Keep(inner) => Insert::Keep(complete::Tier { inner }),
},
Inner::Complete(inner) => Insert::Keep(complete::Tier { inner }),
Inner::Hash(hash) => Insert::Hash(hash),
}
}
}
impl<Item: Focus + Witness + Clone> Witness for Tier<Item>
where
Item::Complete: Witness + Clone,
{
#[inline]
fn witness(&self, index: impl Into<u64>) -> Option<(AuthPath<Self>, Hash)> {
match &self.inner {
Inner::Frontier(frontier) => frontier.witness(index),
Inner::Complete(complete) => complete.witness(index),
Inner::Hash(_) => None,
}
}
}
impl<Item: Focus + GetPosition + Clone> GetPosition for Tier<Item>
where
Item::Complete: Clone,
{
#[inline]
fn position(&self) -> Option<u64> {
match &self.inner {
Inner::Frontier(frontier) => frontier.position(),
Inner::Complete(_) | Inner::Hash(_) => None,
}
}
}
impl<Item: Focus + Forget + Clone> Forget for Tier<Item>
where
Item::Complete: ForgetOwned + Clone,
{
#[inline]
fn forget(&mut self, forgotten: Option<Forgotten>, index: impl Into<u64>) -> bool {
let was_forgotten;
let inner = std::mem::replace(&mut self.inner, Inner::Hash(Hash::zero()));
(was_forgotten, self.inner) = match inner {
Inner::Frontier(mut frontier) => {
(frontier.forget(forgotten, index), Inner::Frontier(frontier))
}
Inner::Complete(complete) => match complete.forget_owned(forgotten, index) {
(Insert::Keep(complete), forgotten) => (forgotten, Inner::Complete(complete)),
(Insert::Hash(hash), forgotten) => (forgotten, Inner::Hash(hash)),
},
Inner::Hash(hash) => (false, Inner::Hash(hash)),
};
was_forgotten
}
}
impl<Item: Focus + Clone> From<complete::Tier<Item::Complete>> for Tier<Item>
where
Item::Complete: Clone,
{
fn from(complete: complete::Tier<Item::Complete>) -> Self {
Self {
inner: Inner::Complete(complete.inner),
}
}
}
impl<Item: Focus + Clone> From<complete::Top<Item::Complete>> for Tier<Item>
where
Item::Complete: Clone,
{
fn from(complete: complete::Top<Item::Complete>) -> Self {
Self {
inner: Inner::Complete(complete.inner),
}
}
}
impl<'tree, Item: Focus + GetPosition + Height + structure::Any<'tree> + Clone>
structure::Any<'tree> for Tier<Item>
where
Item::Complete: structure::Any<'tree> + Clone,
{
fn kind(&self) -> Kind {
Kind::Internal {
height: <Self as Height>::Height::HEIGHT,
}
}
fn forgotten(&self) -> Forgotten {
match &self.inner {
Inner::Frontier(frontier) => (&**frontier as &dyn structure::Any).forgotten(),
Inner::Complete(complete) => (complete as &dyn structure::Any).forgotten(),
Inner::Hash(_) => Forgotten::default(),
}
}
fn children(&'tree self) -> Vec<HashOrNode<'tree>> {
match &self.inner {
Inner::Frontier(frontier) => frontier.children(),
Inner::Complete(complete) => (complete as &dyn structure::Any).children(),
Inner::Hash(_hash) => vec![],
}
}
}
impl<Item: Focus + OutOfOrder + Clone> OutOfOrder for Tier<Item>
where
Item::Complete: OutOfOrderOwned + Clone,
{
fn uninitialized(position: Option<u64>, forgotten: Forgotten) -> Self {
let is_finalized = if let Some(position) = position {
position.trailing_zeros() >= (<Self as Height>::Height::HEIGHT as u32 * 2)
} else {
false
};
Self {
inner: if is_finalized {
Inner::Hash(Hash::uninitialized())
} else {
Inner::Frontier(Box::new(Nested::uninitialized(position, forgotten)))
},
}
}
fn uninitialized_out_of_order_insert_commitment(
&mut self,
index: u64,
commitment: StateCommitment,
) {
let inner = std::mem::replace(&mut self.inner, Inner::Hash(Hash::uninitialized()));
self.inner = match inner {
Inner::Frontier(mut frontier) => {
frontier.uninitialized_out_of_order_insert_commitment(index, commitment);
Inner::Frontier(frontier)
}
Inner::Complete(complete) => {
Inner::Complete(<Nested<Item> as Focus>::Complete::uninitialized_out_of_order_insert_commitment_owned(
Insert::Keep(complete),
index,
commitment,
))
}
Inner::Hash(hash) => {
Inner::Complete(<Nested<Item> as Focus>::Complete::uninitialized_out_of_order_insert_commitment_owned(
Insert::Hash(hash),
index,
commitment,
))
}
};
}
}
impl<Item: Focus + UncheckedSetHash + Clone> UncheckedSetHash for Tier<Item>
where
Item::Complete: UncheckedSetHash + Clone,
{
fn unchecked_set_hash(&mut self, index: u64, height: u8, hash: Hash) {
match &mut self.inner {
Inner::Frontier(frontier) => frontier.unchecked_set_hash(index, height, hash),
Inner::Complete(complete) => complete.unchecked_set_hash(index, height, hash),
Inner::Hash(this_hash) => {
if height == Self::Height::HEIGHT {
*this_hash = hash;
}
}
}
}
fn finish_initialize(&mut self) {
match &mut self.inner {
Inner::Frontier(frontier) => frontier.finish_initialize(),
Inner::Complete(complete) => complete.finish_initialize(),
Inner::Hash(hash) => {
if hash.is_uninitialized() {
*hash = Hash::one();
}
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn position_advances_by_one() {
let mut tier: Tier<Item> = Tier::new(Hash::zero().into());
for expected_position in 1..=(u16::MAX as u64) {
assert_eq!(tier.position(), Some(expected_position));
tier.insert(Hash::zero().into()).unwrap();
}
assert_eq!(tier.position(), None);
}
}