penumbra_sdk_tct/
tree.rs

1use std::{
2    fmt::{Debug, Display},
3    sync::Arc,
4};
5
6use decaf377::Fq;
7use penumbra_sdk_proto::{penumbra::crypto::tct::v1 as pb, DomainType};
8
9use crate::error::*;
10use crate::prelude::{Witness as _, *};
11use crate::Witness;
12
13#[path = "epoch.rs"]
14pub(crate) mod epoch;
15pub(crate) use epoch::block;
16
17/// A sparse merkle tree witnessing up to 65,536 epochs of up to 65,536 blocks of up to 65,536
18/// [`Commitment`]s.
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct Tree {
21    index: HashedMap<StateCommitment, index::within::Tree>,
22    inner: Arc<frontier::Top<frontier::Tier<frontier::Tier<frontier::Item>>>>,
23}
24
25impl Default for Tree {
26    fn default() -> Self {
27        Self {
28            index: HashedMap::default(),
29            inner: Arc::new(frontier::Top::new(frontier::TrackForgotten::Yes)),
30        }
31    }
32}
33
34impl PartialEq for Tree {
35    fn eq(&self, other: &Tree) -> bool {
36        self.position() == other.position() // two trees could have identical contents but different positions
37            && self.root() == other.root() // if the roots match, they represent the same commitments, but may witness different ones
38            && self.index == other.index // we ensure they witness the same commitments by checking equality of indices
39    }
40}
41
42impl Eq for Tree {}
43
44/// The root hash of a [`Tree`].
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
46#[serde(try_from = "pb::MerkleRoot", into = "pb::MerkleRoot")]
47#[cfg_attr(any(test, feature = "arbitrary"), derive(proptest_derive::Arbitrary))]
48pub struct Root(pub Hash);
49
50impl Root {
51    /// Check if this is the root of an empty tree.
52    pub fn is_empty(&self) -> bool {
53        self.0 == Hash::zero()
54    }
55}
56
57impl From<Root> for Fq {
58    fn from(root: Root) -> Self {
59        root.0.into()
60    }
61}
62
63/// An error occurred when decoding a tree root from bytes.
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
65#[error("could not decode tree root")]
66pub struct RootDecodeError;
67
68impl TryFrom<pb::MerkleRoot> for Root {
69    type Error = RootDecodeError;
70
71    fn try_from(root: pb::MerkleRoot) -> Result<Root, Self::Error> {
72        let bytes: [u8; 32] = (&root.inner[..]).try_into().map_err(|_| RootDecodeError)?;
73        let inner = Fq::from_bytes_checked(&bytes).map_err(|_| RootDecodeError)?;
74        Ok(Root(Hash::new(inner)))
75    }
76}
77
78impl From<Root> for pb::MerkleRoot {
79    fn from(root: Root) -> Self {
80        Self {
81            inner: Fq::from(root.0).to_bytes().to_vec(),
82        }
83    }
84}
85
86impl DomainType for Root {
87    type Proto = pb::MerkleRoot;
88}
89
90impl Display for Root {
91    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
92        write!(f, "{}", hex::encode(Fq::from(self.0).to_bytes()))
93    }
94}
95
96/// The index of a [`Commitment`] within a [`Tree`].
97#[derive(
98    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Default,
99)]
100#[cfg_attr(any(test, feature = "arbitrary"), derive(proptest_derive::Arbitrary))]
101pub struct Position(index::within::Tree);
102
103impl Position {
104    /// The index of the [`Commitment`] to which this [`Position`] refers within its own block.
105    pub fn commitment(&self) -> u16 {
106        self.0.commitment.into()
107    }
108
109    /// The index of the block to which this [`Position`] refers within its own epoch.
110    pub fn block(&self) -> u16 {
111        self.0.block.into()
112    }
113
114    /// The index of the epoch to which this [`Position`] refers within its [`Tree`].
115    pub fn epoch(&self) -> u16 {
116        self.0.epoch.into()
117    }
118}
119
120impl From<Position> for u64 {
121    fn from(position: Position) -> Self {
122        position.0.into()
123    }
124}
125
126impl From<u64> for Position {
127    fn from(position: u64) -> Self {
128        Position(position.into())
129    }
130}
131
132impl From<(u16, u16, u16)> for Position {
133    fn from((epoch, block, commitment): (u16, u16, u16)) -> Self {
134        Position(index::within::Tree {
135            epoch: epoch.into(),
136            block: block.into(),
137            commitment: commitment.into(),
138        })
139    }
140}
141
142impl From<Position> for (u16, u16, u16) {
143    fn from(position: Position) -> Self {
144        (position.epoch(), position.block(), position.commitment())
145    }
146}
147
148impl Tree {
149    /// Create a new empty [`Tree`] for storing all commitments to the end of time.
150    pub fn new() -> Self {
151        Self::default()
152    }
153
154    // Assemble a tree from its two parts without checking any invariants.
155    pub(crate) fn unchecked_from_parts(
156        index: HashedMap<StateCommitment, index::within::Tree>,
157        inner: frontier::Top<frontier::Tier<frontier::Tier<frontier::Item>>>,
158    ) -> Self {
159        Self {
160            index,
161            inner: Arc::new(inner),
162        }
163    }
164
165    /// Get the root hash of this [`Tree`].
166    ///
167    /// Internal hashing is performed lazily to prevent unnecessary intermediary hashes from being
168    /// computed, so the first hash returned after a long sequence of insertions may take more time
169    /// than subsequent calls.
170    ///
171    /// Computed hashes are cached so that subsequent calls without further modification are very
172    /// fast.
173    #[instrument(level = "trace", skip(self))]
174    pub fn root(&self) -> Root {
175        let root = Root(self.inner.hash());
176        trace!(?root);
177        root
178    }
179
180    /// Add a new [`Commitment`] to the most recent block of the most recent epoch of this [`Tree`].
181    ///
182    /// If successful, returns the [`Position`] at which the commitment was inserted.
183    ///
184    /// # Errors
185    ///
186    /// Returns [`InsertError`] if any of:
187    ///
188    /// - the [`Tree`] is full,
189    /// - the current epoch is full, or
190    /// - the current block is full.
191    #[instrument(level = "trace", skip(self))]
192    pub fn insert(
193        &mut self,
194        witness: Witness,
195        commitment: StateCommitment,
196    ) -> Result<Position, InsertError> {
197        let item = match witness {
198            Witness::Keep => commitment.into(),
199            Witness::Forget => Hash::of(commitment).into(),
200        };
201
202        // Get the position of the insertion, if it would succeed
203        let position = (self.inner.position().ok_or(InsertError::Full)?).into();
204
205        // Try to insert the commitment into the latest block
206        Arc::make_mut(&mut self.inner)
207            .update(|epoch| {
208                epoch
209                    .update(|block| {
210                        // Don't insert into a finalized block (this will fail); create a new one
211                        // instead (below)
212                        if block.is_finalized() {
213                            return None;
214                        }
215
216                        Some(block
217                            .insert(item)
218                            .map_err(|_| InsertError::BlockFull))
219                    })
220                    .flatten()
221                    // If the latest block was finalized already or doesn't exist, create a new block and
222                    // insert into that block
223                    .or_else(|| {
224                        // Don't insert into a finalized epoch (this will fail); create a new one
225                        // instead (below)
226                        if epoch.is_finalized() {
227                            return None;
228                        }
229
230                        Some(epoch
231                            .insert(frontier::Tier::new(item))
232                            .map_err(|_| InsertError::EpochFull))
233                    })
234            })
235            .flatten()
236            // If the latest epoch was finalized already or doesn't exist, create a new epoch and
237            // insert into that epoch
238            .unwrap_or_else(|| {
239                Arc::make_mut(&mut self.inner)
240                    .insert(frontier::Tier::new(frontier::Tier::new(item)))
241                    .expect("inserting a commitment must succeed because we already checked that the tree is not full");
242                Ok(())
243            })
244            .map_err(|error| {
245                error!(%error); error
246            })?;
247
248        // Keep track of the position of this just-inserted commitment in the index, if it was
249        // slated to be kept
250        if let Witness::Keep = witness {
251            if let Some(replaced) = self.index.insert(commitment, position) {
252                // This case is handled for completeness, but should not happen in
253                // practice because commitments should be unique
254                let forgotten = Arc::make_mut(&mut self.inner).forget(replaced);
255                debug_assert!(forgotten);
256            }
257        }
258
259        let position = Position(position);
260        trace!(?position);
261        Ok(position)
262    }
263
264    /// Get a [`Proof`] of inclusion for the commitment at this index in the tree.
265    ///
266    /// If the index is not witnessed in this tree, return `None`.
267    #[instrument(level = "trace", skip(self))]
268    pub fn witness(&self, commitment: StateCommitment) -> Option<Proof> {
269        let &index = if let Some(index) = self.index.get(&commitment) {
270            index
271        } else {
272            trace!("not witnessed");
273            return None;
274        };
275
276        let (auth_path, leaf) = match self.inner.witness(index) {
277            Some(witness) => witness,
278            None => panic!(
279                "commitment `{commitment:?}` at position `{index:?}` must be witnessed because it is indexed"
280            ),
281        };
282
283        debug_assert_eq!(leaf, Hash::of(commitment));
284
285        let proof = Proof(crate::internal::proof::Proof {
286            position: index.into(),
287            auth_path,
288            leaf: commitment,
289        });
290
291        trace!(?index, ?proof);
292        Some(proof)
293    }
294
295    /// Forget about the witness for the given [`Commitment`].
296    ///
297    /// Returns `true` if the commitment was previously witnessed (and now is forgotten), and `false` if
298    /// it was not witnessed.
299    #[instrument(level = "trace", skip(self))]
300    pub fn forget(&mut self, commitment: StateCommitment) -> bool {
301        let mut forgotten = false;
302
303        if let Some(&within_epoch) = self.index.get(&commitment) {
304            // We forgot something
305            forgotten = true;
306            // Forget the index for this element in the tree
307            let forgotten = Arc::make_mut(&mut self.inner).forget(within_epoch);
308            debug_assert!(forgotten);
309            // Remove this entry from the index
310            self.index.remove(&commitment);
311        }
312
313        trace!(?forgotten);
314        forgotten
315    }
316
317    /// Get the position in this [`Tree`] of the given [`Commitment`], if it is currently witnessed.
318    #[instrument(level = "trace", skip(self))]
319    pub fn position_of(&self, commitment: StateCommitment) -> Option<Position> {
320        let position = self.index.get(&commitment).map(|index| Position(*index));
321        trace!(?position);
322        position
323    }
324
325    /// Add a new block all at once to the most recently inserted epoch of this [`Tree`], returning
326    /// the block root of the finalized block.
327    ///
328    /// This can be used for two purposes:
329    ///
330    /// 1. to insert a [`block::Root`] into the tree as a stand-in for an entire un-witnessed block,
331    ///    or
332    /// 2. to insert a [`block::Builder`] into the tree that was constructed separately.
333    ///
334    /// The latter [`block::Builder`] API only accelerates tree construction when used in parallel,
335    /// but the former [`block::Root`] insertion can be used to accelerate the construction of a
336    /// tree even in a single thread, because if the root is already known, only one set of hashes
337    /// need be performed, rather than performing hashing for each commitment in the block.
338    ///
339    /// This function can be called on anything that implements `Into<block::Finalized>`, in
340    /// particular:
341    ///
342    /// - [`block::Root`] (treated as a finalized block with no witnessed commitments).
343    /// - [`block::Builder`] (the block is finalized as it is inserted), and of course
344    /// - [`block::Finalized`].
345    ///
346    /// # Errors
347    ///
348    /// Returns [`InsertBlockError`] containing the inserted block without adding it to the [`Tree`]
349    /// if the [`Tree`] is full or the current epoch is full.
350    #[instrument(level = "trace", skip(self, block))]
351    pub fn insert_block(
352        &mut self,
353        block: impl Into<block::Finalized>,
354    ) -> Result<block::Root, InsertBlockError> {
355        // We split apart the inside so that we get the right instrumentation when this is called as
356        // an inner function in `end_block`
357        let block_root = self.insert_block_uninstrumented(block).map_err(|error| {
358            error!(%error);
359            error
360        })?;
361        trace!(?block_root);
362        Ok(block_root)
363    }
364
365    fn insert_block_uninstrumented(
366        &mut self,
367        block: impl Into<block::Finalized>,
368    ) -> Result<block::Root, InsertBlockError> {
369        let block::Finalized { inner, index } = block.into();
370
371        // Convert the top level inside of the block to a tier that can be slotted into the epoch
372        // We have this be an `Option` because we need to `take` out of it inside closures
373        let mut inner: Option<frontier::Tier<_>> = Some(match inner {
374            Insert::Keep(inner) => inner.into(),
375            Insert::Hash(hash) => hash.into(),
376        });
377
378        // We have this be an `Option` because we need to `take` out of it in closures
379        let mut index = Some(index);
380
381        // Finalize the latest block, if it exists and is not yet finalized -- this means that
382        // position calculations will be correct, since they will start at the next block
383        Arc::make_mut(&mut self.inner).update(|epoch| epoch.update(|block| block.finalize()));
384
385        // Get the epoch and block index of the next insertion
386        let position = self.inner.position();
387
388        // Insert the block into the latest epoch, or create a new epoch for it if the latest epoch
389        // does not exist or is finalized
390        let block_root = Arc::make_mut(&mut self.inner)
391            .update(|epoch| {
392                // If the epoch is finalized, create a new one (below) to insert the block into
393                if epoch.is_finalized() {
394                    return None;
395                }
396
397                if epoch.is_full() {
398                    // The current epoch would be full when we tried to insert into it
399                    return Some(Err(InsertBlockError::EpochFull(block::Finalized {
400                        inner: inner
401                            .take()
402                            .expect("inner option should be Some")
403                            .finalize_owned()
404                            .map(Into::into),
405                        index: index.take().expect("index option should be Some"),
406                    })));
407                }
408
409                // Get the inner thing from the `Option` storage
410                let inner = inner.take().expect("inner option should be Some");
411
412                // Calculate the block root
413                let block_root = block::Root(inner.hash());
414
415                epoch
416                    .insert(inner)
417                    .expect("inserting into the current epoch must succeed when it is not full");
418
419                Some(Ok(block_root))
420            })
421            .flatten()
422            .unwrap_or_else(|| {
423                if self.inner.is_full() {
424                    return Err(InsertBlockError::Full(block::Finalized {
425                        inner: inner
426                            .take()
427                            .expect("inner option should be Some")
428                            .finalize_owned()
429                            .map(Into::into),
430                        index: index.take().expect("index option should be Some"),
431                    }));
432                }
433
434                // Get the inner thing from the `Option` storage
435                let inner = inner.take().expect("inner option should be Some");
436
437                // Calculate the block root
438                let block_root = block::Root(inner.hash());
439
440                // Create a new epoch and insert the block into it
441                Arc::make_mut(&mut self.inner)
442                    .insert(frontier::Tier::new(inner))
443                    .expect("inserting a new epoch must succeed when the tree is not full");
444
445                Ok(block_root)
446            })?;
447
448        // Extract from the position we recorded earlier what the epoch/block indexes for each
449        // inserted commitment should be
450        let index::within::Tree { epoch, block, .. } = position
451            .expect("insertion succeeded so position must exist")
452            .into();
453
454        // Add the index of all commitments in the block to the global index
455        for (c, index::within::Block { commitment }) in
456            index.take().expect("index option should be Some")
457        {
458            // If any commitment is repeated, forget the previous one within the tree, since it is
459            // now inaccessible
460            if let Some(replaced) = self.index.insert(
461                c,
462                index::within::Tree {
463                    epoch,
464                    block,
465                    commitment,
466                },
467            ) {
468                // This case is handled for completeness, but should not happen in practice because
469                // commitments should be unique
470                let forgotten = Arc::make_mut(&mut self.inner).forget(replaced);
471                debug_assert!(forgotten);
472            }
473        }
474
475        Ok(block_root)
476    }
477
478    /// Explicitly mark the end of the current block in this tree, advancing the position to the
479    /// next block, and returning the root of the block which was just finalized.
480    #[instrument(level = "trace", skip(self))]
481    pub fn end_block(&mut self) -> Result<block::Root, InsertBlockError> {
482        // Check to see if the latest block is already finalized, and finalize it if
483        // it is not
484        let (already_finalized, finalized_root) = Arc::make_mut(&mut self.inner)
485            .update(|epoch| {
486                epoch.update(|tier| match tier.finalize() {
487                    true => (true, block::Finalized::default().root()),
488                    false => (false, block::Root(tier.hash())),
489                })
490            })
491            .flatten()
492            // If the entire tree or the latest epoch is empty or finalized, the latest block is
493            // considered already finalized
494            .unwrap_or((true, block::Finalized::default().root()));
495
496        // If the latest block was already finalized (i.e. we are at the start of an unfinalized
497        // empty block), insert an empty finalized block
498        if already_finalized {
499            self.insert_block_uninstrumented(block::Finalized::default())
500                .map_err(|error| {
501                    error!(%error);
502                    error
503                })?;
504        };
505
506        trace!(finalized_block_root = ?finalized_root);
507        Ok(finalized_root)
508    }
509
510    /// Get the root hash of the most recent block in the most recent epoch of this [`Tree`].
511    #[instrument(level = "trace", skip(self))]
512    pub fn current_block_root(&self) -> block::Root {
513        let root = self
514            .inner
515            .focus()
516            .and_then(|epoch| {
517                let block = epoch.focus()?;
518                if block.is_finalized() {
519                    None
520                } else {
521                    Some(block::Root(block.hash()))
522                }
523            })
524            // If there is no latest unfinalized block, we return the hash of the empty unfinalized block
525            .unwrap_or_else(|| block::Builder::default().root());
526        trace!(?root);
527        root
528    }
529
530    /// Add a new epoch all at once to this [`Tree`], returning the root of the finalized epoch
531    /// which was inserted.
532    ///
533    /// This can be used for two purposes:
534    ///
535    /// 1. to insert an [`epoch::Root`] into the tree as a stand-in for an entire un-witnessed block,
536    ///    or
537    /// 2. to insert an [`epoch::Builder`] into the tree that was constructed separately.
538    ///
539    /// The latter [`epoch::Builder`] API only accelerates tree construction when used in parallel,
540    /// but the former [`epoch::Root`] insertion can be used to accelerate the construction of a
541    /// tree even in a single thread, because if the root is already known, only one set of hashes
542    /// need be performed, rather than performing hashing for each commitment in the epoch.
543    ///
544    /// This function can be called on anything that implements `Into<epoch::Finalized>`, in
545    /// particular:
546    ///
547    /// - [`epoch::Root`] (treated as a finalized epoch with no witnessed commitments).
548    /// - [`epoch::Builder`] (the epoch is finalized as it is inserted), and of course
549    /// - [`epoch::Finalized`].
550    ///
551    /// # Errors
552    ///
553    /// Returns [`InsertEpochError`] containing the epoch without adding it to the [`Tree`] if the
554    /// [`Tree`] is full.
555    #[instrument(level = "trace", skip(self, epoch))]
556    pub fn insert_epoch(
557        &mut self,
558        epoch: impl Into<epoch::Finalized>,
559    ) -> Result<epoch::Root, InsertEpochError> {
560        // We split apart the inside so that we get the right instrumention when this is called as
561        // an inner function in `end_epoch`
562        let epoch_root = self.insert_epoch_uninstrumented(epoch).map_err(|error| {
563            error!(%error);
564            error
565        })?;
566        trace!(?epoch_root);
567        Ok(epoch_root)
568    }
569
570    fn insert_epoch_uninstrumented(
571        &mut self,
572        epoch: impl Into<epoch::Finalized>,
573    ) -> Result<epoch::Root, InsertEpochError> {
574        let epoch::Finalized { inner, index } = epoch.into();
575
576        // If the insertion would fail, return an error
577        if self.inner.is_full() {
578            // There is no room for another epoch to be inserted into the tree
579            return Err(InsertEpochError(epoch::Finalized { inner, index }));
580        }
581
582        // Convert the top level inside of the epoch to a tier that can be slotted into the tree
583        let inner: frontier::Tier<frontier::Tier<frontier::Item>> = match inner {
584            Insert::Keep(inner) => inner.into(),
585            Insert::Hash(hash) => hash.into(),
586        };
587
588        // Finalize the latest epoch, if it exists and is not yet finalized -- this means that
589        // position calculations will be correct, since they will start at the next epoch
590        Arc::make_mut(&mut self.inner).update(|epoch| epoch.finalize());
591
592        // Get the epoch index of the next insertion
593        let index::within::Tree { epoch, .. } = self
594            .inner
595            .position()
596            .expect("tree must have a position because it is not full")
597            .into();
598
599        // Calculate the root of the finalized epoch we're about to insert
600        let epoch_root = epoch::Root(inner.hash());
601
602        // Insert the inner tree of the epoch into the global tree
603        Arc::make_mut(&mut self.inner)
604            .insert(inner)
605            .expect("inserting an epoch must succeed when tree is not full");
606
607        // Add the index of all commitments in the epoch to the global tree index
608        for (c, index::within::Epoch { block, commitment }) in index {
609            // If any commitment is repeated, forget the previous one within the tree, since it is
610            // now inaccessible
611            if let Some(replaced) = self.index.insert(
612                c,
613                index::within::Tree {
614                    epoch,
615                    block,
616                    commitment,
617                },
618            ) {
619                // This case is handled for completeness, but should not happen in practice because
620                // commitments should be unique
621                let forgotten = Arc::make_mut(&mut self.inner).forget(replaced);
622                debug_assert!(forgotten);
623            }
624        }
625
626        Ok(epoch_root)
627    }
628
629    /// Explicitly mark the end of the current epoch in this tree, advancing the position to the
630    /// next epoch, and returning the root of the epoch which was just finalized.
631    #[instrument(level = "trace", skip(self))]
632    pub fn end_epoch(&mut self) -> Result<epoch::Root, InsertEpochError> {
633        // Check to see if the latest block is already finalized, and finalize it if
634        // it is not
635        let (already_finalized, finalized_root) = Arc::make_mut(&mut self.inner)
636            .update(|tier| match tier.finalize() {
637                true => (true, epoch::Finalized::default().root()),
638                false => (false, epoch::Root(tier.hash())),
639            })
640            // If there is no focused block, the latest block is considered already finalized
641            .unwrap_or((true, epoch::Finalized::default().root()));
642
643        // If the latest block was already finalized (i.e. we are at the start of an unfinalized
644        // empty block), insert an empty finalized block
645        if already_finalized {
646            self.insert_epoch_uninstrumented(epoch::Finalized::default())
647                .map_err(|error| {
648                    error!(%error);
649                    error
650                })?;
651        };
652
653        trace!(finalized_epoch_root = ?finalized_root);
654        Ok(finalized_root)
655    }
656
657    /// Get the root hash of the most recent epoch in this [`Tree`].
658    #[instrument(level = "trace", skip(self))]
659    pub fn current_epoch_root(&self) -> epoch::Root {
660        let root = self
661            .inner
662            .focus()
663            .and_then(|epoch| {
664                if epoch.is_finalized() {
665                    None
666                } else {
667                    Some(epoch::Root(epoch.hash()))
668                }
669            })
670            // In the case where there is no latest unfinalized epoch, we return the hash of the
671            // empty unfinalized epoch
672            .unwrap_or_else(|| epoch::Builder::default().root());
673        trace!(?root);
674        root
675    }
676
677    /// The position in this [`Tree`] at which the next [`Commitment`] would be inserted.
678    ///
679    /// If the [`Tree`] is full, returns `None`.
680    ///
681    /// The maximum capacity of a [`Tree`] is 281,474,976,710,656 = 65,536 epochs of 65,536
682    /// blocks of 65,536 [`Commitment`]s.
683    ///
684    /// Note that [`forget`](Tree::forget)ting a commitment does not decrease this; it only
685    /// decreases the [`witnessed_count`](Tree::witnessed_count).
686    #[instrument(level = "trace", skip(self))]
687    pub fn position(&self) -> Option<Position> {
688        let position = self.inner.position().map(|p| Position(p.into()));
689        trace!(?position);
690        position
691    }
692
693    /// The count of how many commitments have been forgotten explicitly using
694    /// [`forget`](Tree::forget), or implicitly by being overwritten by a subsequent insertion of
695    /// the _same_ commitment (this case is rare in practice).
696    ///
697    /// This does not include commitments that were inserted using [`Witness::Forget`], only those
698    /// forgotten subsequent to their insertion.
699    #[instrument(level = "trace", skip(self))]
700    pub fn forgotten(&self) -> Forgotten {
701        let forgotten = self
702            .inner
703            .forgotten()
704            .expect("inner `Top` of `Tree` must always be in forgotten-tracking mode");
705        trace!(?forgotten);
706        forgotten
707    }
708
709    /// The number of [`Commitment`]s currently witnessed in this [`Tree`].
710    ///
711    /// Note that [`forget`](Tree::forget)ting a commitment decreases this count, but does not
712    /// decrease the [`position`](Tree::position) of the next inserted [`Commitment`].
713    #[instrument(level = "trace", skip(self))]
714    pub fn witnessed_count(&self) -> usize {
715        let count = self.index.len();
716        trace!(?count);
717        count
718    }
719
720    /// Check whether this [`Tree`] is empty.
721    #[instrument(level = "trace", skip(self))]
722    pub fn is_empty(&self) -> bool {
723        let is_empty = self.inner.is_empty();
724        trace!(?is_empty);
725        is_empty
726    }
727
728    /// Get an iterator over all commitments currently witnessed in the tree, **ordered by
729    /// position**.
730    ///
731    /// Unlike [`commitments_unordered`](Tree::commitments_unordered), this guarantees that
732    /// commitments will be returned in order, but it may be slower by a constant factor.
733    #[instrument(level = "trace", skip(self))]
734    pub fn commitments(
735        &self,
736    ) -> impl Iterator<Item = (Position, StateCommitment)> + Send + Sync + '_ {
737        crate::storage::serialize::Serializer::default().commitments(self)
738    }
739
740    /// Get an iterator over all commitments currently witnessed in the tree.
741    ///
742    /// Unlike [`commitments`](Tree::commitments), this **does not** guarantee that commitments will
743    /// be returned in order, but it may be faster by a constant factor.
744    #[instrument(level = "trace", skip(self))]
745    pub fn commitments_unordered(
746        &self,
747    ) -> impl Iterator<Item = (StateCommitment, Position)> + Send + Sync + '_ {
748        self.index.iter().map(|(c, p)| (*c, Position(*p)))
749    }
750
751    /// Get a dynamic representation of the internal structure of the tree, which can be traversed
752    /// and inspected arbitrarily.
753    pub fn structure(&self) -> structure::Node {
754        let _structure_span = trace_span!("structure");
755        // TODO: use the structure span for instrumenting methods of the structure, as it is traversed
756        Node::root(&*self.inner)
757    }
758
759    /// Deserialize a tree from a [`storage::Read`] of its contents, without checking for internal
760    /// consistency.
761    ///
762    /// This can be more convenient than [`Tree::load`], since it is able to internally query the
763    /// storage for the last position and forgotten count.
764    ///
765    /// ⚠️ **WARNING:** Do not deserialize trees you did not serialize yourself, or risk violating
766    /// internal invariants.
767    pub fn from_reader<R: Read>(reader: &mut R) -> Result<Tree, R::Error> {
768        storage::deserialize::from_reader(reader)
769    }
770
771    /// Serialize the tree incrementally from the last stored [`Position`] and [`Forgotten`]
772    /// specified, into a [`storage::Write`], performing only the operations necessary to serialize
773    /// the changes to the tree.
774    ///
775    /// This can be more convenient than using [`Tree::updates`], because it is able to internally
776    /// query the storage for the last position and forgotten count, and drive the storage
777    /// operations itself.
778    pub fn to_writer<W: Write>(&self, writer: &mut W) -> Result<(), W::Error> {
779        storage::serialize::to_writer(writer, self)
780    }
781
782    /// Deserialize a tree from a [`storage::AsyncRead`] of its contents, without checking for
783    /// internal consistency.
784    ///
785    /// This can be more convenient than [`Tree::load`], since it is able to internally query the
786    /// storage for the last position and forgotten count.
787    ///
788    /// ⚠️ **WARNING:** Do not deserialize trees you did not serialize yourself, or risk violating
789    /// internal invariants.
790    pub async fn from_async_reader<R: AsyncRead>(reader: &mut R) -> Result<Tree, R::Error> {
791        storage::deserialize::from_async_reader(reader).await
792    }
793
794    /// Serialize the tree incrementally from the last stored [`Position`] and [`Forgotten`]
795    /// specified, into a [`storage::AsyncWrite`], performing only the operations necessary to
796    /// serialize the changes to the tree.
797    ///
798    /// This can be more convenient than using [`Tree::updates`], because it is able to internally
799    /// query the storage for the last position and forgotten count, and drive the storage
800    /// operations itself.
801    pub async fn to_async_writer<W: AsyncWrite>(&self, writer: &mut W) -> Result<(), W::Error> {
802        storage::serialize::to_async_writer(writer, self).await
803    }
804
805    /// Deserialize a tree using externally driven iteration, without checking for internal
806    /// consistency.
807    ///
808    /// Reconstructing a [`Tree`] using this method requires stepping through a series of states, as
809    /// follows:
810    ///
811    /// 1. [`Tree::load`] returns an object [`LoadCommitments`](storage::LoadCommitments) which can
812    ///    be used to [`insert`](storage::LoadCommitments::insert) positioned commitments.
813    /// 2. When all commitments have been inserted, call
814    ///    [`.load_hashes()`](storage::LoadCommitments::load_hashes) to get an object
815    ///    [`LoadHashes`](storage::LoadHashes).
816    /// 3. [`LoadHashes`](storage::LoadHashes) can be used to
817    ///    [`insert`](storage::LoadHashes::insert) positioned, heighted hashes.
818    /// 4. Finally, call [`.finish()`](storage::LoadHashes::finish) on the
819    ///    [`LoadHashes`](storage::LoadHashes) to get the [`Tree`].
820    ///
821    /// ⚠️ **WARNING:** Do not deserialize trees you did not serialize yourself, or risk violating
822    /// internal invariants. You *must* insert all the commitments and hashes corresponding to the
823    /// stored tree, or the reconstructed tree will not match what was serialized, and further, it
824    /// may have internal inconsistencies that will mean that the proofs it produces will not
825    /// verify.
826    ///
827    /// ℹ️ **NOTE:** You may prefer to use [`from_reader`](Tree::from_reader) or
828    /// [`from_async_reader`](Tree::from_async_reader), which drive the iteration over the
829    /// underlying storage *internally* rather than requiring the caller to drive the iteration.
830    /// [`Tree::load`] is predominanly useful in circumstances when this inversion of control does
831    /// not make sense.
832    pub fn load(
833        last_position: impl Into<StoredPosition>,
834        last_forgotten: Forgotten,
835    ) -> storage::deserialize::LoadCommitments {
836        storage::deserialize::LoadCommitments::new(last_position, last_forgotten)
837    }
838
839    /// Serialize the tree incrementally from the last stored [`Position`] and [`Forgotten`]
840    /// specified, into an iterator of [`storage::Update`]s.
841    ///
842    /// This returns only the operations necessary to serialize the changes to the tree,
843    /// synchronizing the in-memory representation with what is stored.
844    ///
845    /// The iterator of updates may be [`.collect()`](Iterator::collect)ed into a
846    /// [`storage::Updates`], which is more compact in-memory than
847    /// [`.collect()`](Iterator::collect)ing into a [`Vec<Update>`](Vec).
848    ///
849    /// ℹ️ **NOTE:** You may prefer to use [`to_writer`](Tree::to_writer) or
850    /// [`to_async_writer`](Tree::to_async_writer), which drive the operations on the underlying
851    /// storage *internally* rather than requiring the caller to drive iteration. [`Tree::updates`]
852    /// is predominantly useful in circumstances when this inversion of control does not make sense.
853    pub fn updates(
854        &self,
855        last_position: impl Into<StoredPosition>,
856        last_forgotten: Forgotten,
857    ) -> impl Iterator<Item = Update> + Send + Sync + '_ {
858        storage::serialize::updates(last_position.into(), last_forgotten, self)
859    }
860}
861
862impl From<frontier::Top<frontier::Tier<frontier::Tier<frontier::Item>>>> for Tree {
863    fn from(inner: frontier::Top<frontier::Tier<frontier::Tier<frontier::Item>>>) -> Self {
864        let mut index = HashedMap::default();
865
866        // Traverse the tree to reconstruct the index
867        let mut stack = vec![Node::root(&inner)];
868        while let Some(node) = stack.pop() {
869            stack.extend(node.children());
870
871            if let structure::Kind::Leaf {
872                commitment: Some(commitment),
873            } = node.kind()
874            {
875                index.insert(commitment, node.position().0);
876            }
877        }
878
879        Self {
880            inner: Arc::new(inner),
881            index,
882        }
883    }
884}