penumbra_sdk_tct/internal/frontier/
tier.rs1use std::fmt::Debug;
2
3use serde::{Deserialize, Serialize};
4
5use crate::prelude::*;
6
7#[derive(Derivative, Serialize, Deserialize)]
9#[derivative(
10 Debug(bound = "Item: Debug, Item::Complete: Debug"),
11 Clone(bound = "Item: Clone, Item::Complete: Clone")
12)]
13#[serde(bound(
14 serialize = "Item: Serialize, Item::Complete: Serialize",
15 deserialize = "Item: Deserialize<'de>, Item::Complete: Deserialize<'de>"
16))]
17pub struct Tier<Item: Focus + Clone>
18where
19 Item::Complete: Clone,
20{
21 inner: Inner<Item>,
22}
23
24type N<Focus> = frontier::Node<Focus>;
25type L<Item> = frontier::Leaf<Item>;
26
27pub type Nested<Item> = N<N<N<N<N<N<N<N<L<Item>>>>>>>>>;
29#[derive(Derivative, Serialize, Deserialize)]
33#[derivative(
34 Debug(bound = "Item: Debug, Item::Complete: Debug"),
35 Clone(bound = "Item: Clone, Item::Complete: Clone")
36)]
37#[serde(bound(
38 serialize = "Item: Serialize, Item::Complete: Serialize + Clone",
39 deserialize = "Item: Deserialize<'de>, Item::Complete: Deserialize<'de>"
40))]
41pub enum Inner<Item: Focus + Clone>
42where
43 Item::Complete: Clone,
44{
45 Frontier(Box<Nested<Item>>),
47 Complete(complete::Nested<Item::Complete>),
49 Hash(Hash),
52}
53
54impl<Item: Focus + Clone> From<Hash> for Tier<Item>
55where
56 Item::Complete: Clone,
57{
58 #[inline]
59 fn from(hash: Hash) -> Self {
60 Self {
61 inner: Inner::Hash(hash),
62 }
63 }
64}
65
66impl<Item: Focus + Clone> Tier<Item>
67where
68 Item::Complete: Clone,
69{
70 #[inline]
72 pub fn new(item: Item) -> Self {
73 Self {
74 inner: Inner::Frontier(Box::new(Nested::new(item))),
75 }
76 }
77
78 #[inline]
82 pub fn insert(&mut self, item: Item) -> Result<(), Item> {
83 let inner = std::mem::replace(&mut self.inner, Inner::Hash(Hash::zero()));
85
86 let result;
87 (result, *self) = match (Self { inner }.insert_owned(item)) {
88 Ok(this) => (Ok(()), this),
89 Err((item, this)) => (Err(item), this),
90 };
91
92 result
93 }
94
95 #[inline]
96 fn insert_owned(self, item: Item) -> Result<Self, (Item, Self)> {
97 match self.inner {
98 inner @ (Inner::Complete(_) | Inner::Hash(_)) => Err((item, Self { inner })),
100 Inner::Frontier(frontier) => {
102 if frontier.is_full() {
103 Err((
106 item,
107 Self {
108 inner: Inner::Frontier(frontier),
109 },
110 ))
111 } else {
112 let inner =
114 Inner::Frontier(Box::new(frontier.insert_owned(item).unwrap_or_else(
115 |_| panic!("frontier is not full, so insert must succeed"),
116 )));
117 Ok(Self { inner })
118 }
119 }
120 }
121 }
122
123 #[inline]
127 pub fn update<T>(&mut self, f: impl FnOnce(&mut Item) -> T) -> Option<T> {
128 if let Inner::Frontier(frontier) = &mut self.inner {
129 frontier.update(f)
130 } else {
131 None
132 }
133 }
134
135 #[inline]
139 pub fn focus(&self) -> Option<&Item> {
140 if let Inner::Frontier(frontier) = &self.inner {
141 frontier.focus()
142 } else {
143 None
144 }
145 }
146
147 #[inline]
151 pub fn is_full(&self) -> bool {
152 match &self.inner {
153 Inner::Frontier(frontier) => frontier.is_full(),
154 Inner::Complete(_) | Inner::Hash(_) => true,
155 }
156 }
157
158 #[inline]
160 pub fn finalize(&mut self) -> bool {
161 let already_finalized = self.is_finalized();
162
163 let inner = std::mem::replace(&mut self.inner, Inner::Hash(Hash::zero()));
166
167 self.inner = match inner {
168 Inner::Frontier(frontier) => match frontier.finalize_owned() {
169 Insert::Hash(hash) => Inner::Hash(hash),
170 Insert::Keep(inner) => Inner::Complete(inner),
171 },
172 inner @ (Inner::Complete(_) | Inner::Hash(_)) => inner,
173 };
174
175 already_finalized
176 }
177
178 #[inline]
180 pub fn is_finalized(&self) -> bool {
181 match self.inner {
182 Inner::Frontier(_) => false,
183 Inner::Complete(_) | Inner::Hash(_) => true,
184 }
185 }
186}
187
188impl<Item: Focus + Clone> Height for Tier<Item>
189where
190 Item::Complete: Clone,
191{
192 type Height = <Nested<Item> as Height>::Height;
193}
194
195impl<Item: Focus + Clone> GetHash for Tier<Item>
196where
197 Item::Complete: Clone,
198{
199 #[inline]
200 fn hash(&self) -> Hash {
201 match &self.inner {
202 Inner::Frontier(frontier) => frontier.hash(),
203 Inner::Complete(complete) => complete.hash(),
204 Inner::Hash(hash) => *hash,
205 }
206 }
207
208 #[inline]
209 fn cached_hash(&self) -> Option<Hash> {
210 match &self.inner {
211 Inner::Frontier(frontier) => frontier.cached_hash(),
212 Inner::Complete(complete) => complete.cached_hash(),
213 Inner::Hash(hash) => Some(*hash),
214 }
215 }
216}
217
218impl<Item: Focus + Clone> Focus for Tier<Item>
219where
220 Item::Complete: Clone,
221{
222 type Complete = complete::Tier<Item::Complete>;
223
224 #[inline]
225 fn finalize_owned(self) -> Insert<Self::Complete> {
226 match self.inner {
227 Inner::Frontier(frontier) => match frontier.finalize_owned() {
228 Insert::Hash(hash) => Insert::Hash(hash),
229 Insert::Keep(inner) => Insert::Keep(complete::Tier { inner }),
230 },
231 Inner::Complete(inner) => Insert::Keep(complete::Tier { inner }),
232 Inner::Hash(hash) => Insert::Hash(hash),
233 }
234 }
235}
236
237impl<Item: Focus + Witness + Clone> Witness for Tier<Item>
238where
239 Item::Complete: Witness + Clone,
240{
241 #[inline]
242 fn witness(&self, index: impl Into<u64>) -> Option<(AuthPath<Self>, Hash)> {
243 match &self.inner {
244 Inner::Frontier(frontier) => frontier.witness(index),
245 Inner::Complete(complete) => complete.witness(index),
246 Inner::Hash(_) => None,
247 }
248 }
249}
250
251impl<Item: Focus + GetPosition + Clone> GetPosition for Tier<Item>
252where
253 Item::Complete: Clone,
254{
255 #[inline]
256 fn position(&self) -> Option<u64> {
257 match &self.inner {
258 Inner::Frontier(frontier) => frontier.position(),
259 Inner::Complete(_) | Inner::Hash(_) => None,
260 }
261 }
262}
263
264impl<Item: Focus + Forget + Clone> Forget for Tier<Item>
265where
266 Item::Complete: ForgetOwned + Clone,
267{
268 #[inline]
269 fn forget(&mut self, forgotten: Option<Forgotten>, index: impl Into<u64>) -> bool {
270 let was_forgotten;
272
273 let inner = std::mem::replace(&mut self.inner, Inner::Hash(Hash::zero()));
276
277 (was_forgotten, self.inner) = match inner {
278 Inner::Frontier(mut frontier) => {
280 (frontier.forget(forgotten, index), Inner::Frontier(frontier))
281 }
282 Inner::Complete(complete) => match complete.forget_owned(forgotten, index) {
285 (Insert::Keep(complete), forgotten) => (forgotten, Inner::Complete(complete)),
286 (Insert::Hash(hash), forgotten) => (forgotten, Inner::Hash(hash)),
287 },
288 Inner::Hash(hash) => (false, Inner::Hash(hash)),
290 };
291
292 was_forgotten
294 }
295}
296
297impl<Item: Focus + Clone> From<complete::Tier<Item::Complete>> for Tier<Item>
298where
299 Item::Complete: Clone,
300{
301 fn from(complete: complete::Tier<Item::Complete>) -> Self {
302 Self {
303 inner: Inner::Complete(complete.inner),
304 }
305 }
306}
307
308impl<Item: Focus + Clone> From<complete::Top<Item::Complete>> for Tier<Item>
309where
310 Item::Complete: Clone,
311{
312 fn from(complete: complete::Top<Item::Complete>) -> Self {
313 Self {
314 inner: Inner::Complete(complete.inner),
315 }
316 }
317}
318
319impl<'tree, Item: Focus + GetPosition + Height + structure::Any<'tree> + Clone>
320 structure::Any<'tree> for Tier<Item>
321where
322 Item::Complete: structure::Any<'tree> + Clone,
323{
324 fn kind(&self) -> Kind {
325 Kind::Internal {
326 height: <Self as Height>::Height::HEIGHT,
327 }
328 }
329
330 fn forgotten(&self) -> Forgotten {
331 match &self.inner {
332 Inner::Frontier(frontier) => (&**frontier as &dyn structure::Any).forgotten(),
333 Inner::Complete(complete) => (complete as &dyn structure::Any).forgotten(),
334 Inner::Hash(_) => Forgotten::default(),
335 }
336 }
337
338 fn children(&'tree self) -> Vec<HashOrNode<'tree>> {
339 match &self.inner {
340 Inner::Frontier(frontier) => frontier.children(),
341 Inner::Complete(complete) => (complete as &dyn structure::Any).children(),
342 Inner::Hash(_hash) => vec![],
343 }
344 }
345}
346
347impl<Item: Focus + OutOfOrder + Clone> OutOfOrder for Tier<Item>
348where
349 Item::Complete: OutOfOrderOwned + Clone,
350{
351 fn uninitialized(position: Option<u64>, forgotten: Forgotten) -> Self {
352 let is_finalized = if let Some(position) = position {
355 position.trailing_zeros() >= (<Self as Height>::Height::HEIGHT as u32 * 2)
359 } else {
360 false
366 };
367
368 Self {
369 inner: if is_finalized {
370 Inner::Hash(Hash::uninitialized())
375 } else {
376 Inner::Frontier(Box::new(Nested::uninitialized(position, forgotten)))
379 },
380 }
381 }
382
383 fn uninitialized_out_of_order_insert_commitment(
384 &mut self,
385 index: u64,
386 commitment: StateCommitment,
387 ) {
388 let inner = std::mem::replace(&mut self.inner, Inner::Hash(Hash::uninitialized()));
391 self.inner = match inner {
392 Inner::Frontier(mut frontier) => {
393 frontier.uninitialized_out_of_order_insert_commitment(index, commitment);
395 Inner::Frontier(frontier)
396 }
397 Inner::Complete(complete) => {
398 Inner::Complete(<Nested<Item> as Focus>::Complete::uninitialized_out_of_order_insert_commitment_owned(
401 Insert::Keep(complete),
402 index,
403 commitment,
404 ))
405 }
406 Inner::Hash(hash) => {
407 Inner::Complete(<Nested<Item> as Focus>::Complete::uninitialized_out_of_order_insert_commitment_owned(
410 Insert::Hash(hash),
411 index,
412 commitment,
413 ))
414 }
415 };
416 }
417}
418
419impl<Item: Focus + UncheckedSetHash + Clone> UncheckedSetHash for Tier<Item>
420where
421 Item::Complete: UncheckedSetHash + Clone,
422{
423 fn unchecked_set_hash(&mut self, index: u64, height: u8, hash: Hash) {
424 match &mut self.inner {
425 Inner::Frontier(frontier) => frontier.unchecked_set_hash(index, height, hash),
426 Inner::Complete(complete) => complete.unchecked_set_hash(index, height, hash),
427 Inner::Hash(this_hash) => {
428 if height == Self::Height::HEIGHT {
429 *this_hash = hash;
430 }
431 }
432 }
433 }
434
435 fn finish_initialize(&mut self) {
436 match &mut self.inner {
437 Inner::Frontier(frontier) => frontier.finish_initialize(),
438 Inner::Complete(complete) => complete.finish_initialize(),
439 Inner::Hash(hash) => {
440 if hash.is_uninitialized() {
441 *hash = Hash::one();
443 }
444 }
445 }
446 }
447}
448
449#[cfg(test)]
450mod test {
451 use super::*;
452
453 #[test]
454 fn position_advances_by_one() {
455 let mut tier: Tier<Item> = Tier::new(Hash::zero().into());
456 for expected_position in 1..=(u16::MAX as u64) {
457 assert_eq!(tier.position(), Some(expected_position));
458 tier.insert(Hash::zero().into()).unwrap();
459 }
460 assert_eq!(tier.position(), None);
461 }
462}