bridgetree/lib.rs
1//! # `bridgetree`
2//!
3//! This crate provides an implementation of an append-only Merkle tree structure. Individual
4//! leaves of the merkle tree may be marked such that witnesses will be maintained for the marked
5//! leaves as additional nodes are appended to the tree, but leaf and node data not specifically
6//! required to maintain these witnesses is not retained, for space efficiency. The data structure
7//! also supports checkpointing of the tree state such that the tree may be reset to a previously
8//! checkpointed state, up to a fixed number of checkpoints.
9//!
10//! The crate also supports using "bridges" containing the minimal possible amount of data to
11//! advance witnesses for marked leaves data up to recent checkpoints or the the latest state of
12//! the tree without having to append each intermediate leaf individually, given a bridge between
13//! the desired states computed by an outside source. The state of the tree is internally
14//! represented as a set of such bridges, and the data structure supports fusing and splitting of
15//! bridges.
16//!
17//! ## Marking
18//!
19//! Merkle trees can be used to show that a value exists in the tree by providing a witness
20//! to a leaf value. We provide an API that allows us to mark the current leaf as a value we wish
21//! to compute witnesses for even after the tree has been appended to in the future; this is called
22//! maintaining a witness. When we're later no longer in a leaf, we can remove the mark and drop
23//! the now unnecessary information from the structure.
24//!
25//! ## Checkpoints and Rollbacks
26//!
27//! This data structure supports a limited capability to restore previous states of the Merkle
28//! tree. It is possible identify the current state of the tree as a "checkpoint" to which the tree
29//! can be reset, and later remove checkpoints that we're no longer interested in being able to
30//! reset the state to.
31//!
32//! In this module, the term "ommer" is used as for the sibling of a parent node in a binary tree.
33pub use incrementalmerkletree::{
34 frontier::{Frontier, NonEmptyFrontier},
35 Address, Hashable, Level, Position, Retention, Source,
36};
37use std::collections::{BTreeMap, BTreeSet, VecDeque};
38use std::fmt::Debug;
39use std::ops::Range;
40
41/// Errors that can be discovered during checks that verify the compatibility of adjacent bridges.
42#[derive(Clone, Debug, PartialEq, Eq)]
43pub enum ContinuityError {
44 /// Returned when a bridge with no prior position information is
45 PriorPositionNotFound,
46 /// Returned when the subsequent bridge's prior position does not match the position of the
47 /// prior bridge's frontier.
48 PositionMismatch(Position, Position),
49}
50
51/// Errors that can be discovered during the process of attempting to create
52/// the witness for a leaf node.
53#[derive(Clone, Debug, PartialEq, Eq)]
54pub enum WitnessingError {
55 AuthBaseNotFound,
56 CheckpointInvalid,
57 CheckpointTooDeep(usize),
58 PositionNotMarked(Position),
59 BridgeFusionError(ContinuityError),
60 BridgeAddressInvalid(Address),
61}
62
63/// The information required to "update" witnesses from one state of a Merkle tree to another.
64///
65/// The witness for a particular leaf of a Merkle tree consists of the siblings of that leaf, plus
66/// the siblings of the parents of that leaf in a path to the root of the tree. When considering a
67/// Merkle tree where leaves are appended to the tree in a linear fashion (rather than being
68/// inserted at arbitrary positions), we often wish to produce a witness for a leaf that was
69/// appended to the tree at some point in the past. A [`MerkleBridge`] from one position in the
70/// tree to another position in the tree contains the minimal amount of information necessary to
71/// produce a witness for the leaf at the former position, given that leaves have been subsequently
72/// appended to reach the current position.
73///
74/// [`MerkleBridge`] values have a semigroup, such that the sum (`fuse`d) value of two successive
75/// bridges, along with a [`NonEmptyFrontier`] with its tip at the prior position of the first bridge
76/// being fused, can be used to produce a witness for the leaf at the tip of the prior frontier.
77#[derive(Clone, Debug, PartialEq, Eq)]
78pub struct MerkleBridge<H> {
79 /// The position of the final leaf in the frontier of the bridge that this bridge is the
80 /// successor of, or None if this is the first bridge in a tree.
81 prior_position: Option<Position>,
82 /// The set of addresses for which we are waiting to discover the ommers. The values of this
83 /// set and the keys of the `need` map should always be disjoint. Also, this set should
84 /// never contain an address for which the sibling value has been discovered; at that point,
85 /// the address is replaced in this set with its parent and the address/sibling pair is stored
86 /// in `ommers`.
87 ///
88 /// Another way to consider the contents of this set is that the values that exist in
89 /// `ommers`, combined with the values in previous bridges' `ommers` and an original leaf
90 /// node, already contain all the values needed to compute the value at the given address.
91 /// Therefore, we are tracking that address as we do not yet have enough information to compute
92 /// its sibling without filling the sibling subtree with empty nodes.
93 tracking: BTreeSet<Address>,
94 /// A map from addresses that were being tracked to the values of their ommers that have been
95 /// discovered while scanning this bridge's range by adding leaves to the bridge's frontier.
96 ommers: BTreeMap<Address, H>,
97 /// The leading edge of the bridge.
98 frontier: NonEmptyFrontier<H>,
99}
100
101impl<H> MerkleBridge<H> {
102 /// Construct a new Merkle bridge containing only the specified
103 /// leaf.
104 pub fn new(value: H) -> Self {
105 Self {
106 prior_position: None,
107 tracking: BTreeSet::new(),
108 ommers: BTreeMap::new(),
109 frontier: NonEmptyFrontier::new(value),
110 }
111 }
112
113 /// Construct a new Merkle bridge from its constituent parts.
114 pub fn from_parts(
115 prior_position: Option<Position>,
116 tracking: BTreeSet<Address>,
117 ommers: BTreeMap<Address, H>,
118 frontier: NonEmptyFrontier<H>,
119 ) -> Self {
120 Self {
121 prior_position,
122 tracking,
123 ommers,
124 frontier,
125 }
126 }
127
128 /// Returns the position of the final leaf in the frontier of the
129 /// bridge that this bridge is the successor of, or None
130 /// if this is the first bridge in a tree.
131 pub fn prior_position(&self) -> Option<Position> {
132 self.prior_position
133 }
134
135 /// Returns the position of the most recently appended leaf.
136 pub fn position(&self) -> Position {
137 self.frontier.position()
138 }
139
140 /// Returns the set of internal node addresses that we're searching
141 /// for the ommers for.
142 pub fn tracking(&self) -> &BTreeSet<Address> {
143 &self.tracking
144 }
145
146 /// Returns the set of internal node addresses that we're searching
147 /// for the ommers for.
148 pub fn ommers(&self) -> &BTreeMap<Address, H> {
149 &self.ommers
150 }
151
152 /// Returns the non-empty frontier of this Merkle bridge.
153 pub fn frontier(&self) -> &NonEmptyFrontier<H> {
154 &self.frontier
155 }
156
157 /// Returns the value of the most recently appended leaf.
158 pub fn current_leaf(&self) -> &H {
159 self.frontier.leaf()
160 }
161
162 /// Checks whether this bridge is a valid successor for the specified
163 /// bridge.
164 pub fn check_continuity(&self, next: &Self) -> Result<(), ContinuityError> {
165 if let Some(pos) = next.prior_position {
166 if pos == self.frontier.position() {
167 Ok(())
168 } else {
169 Err(ContinuityError::PositionMismatch(
170 self.frontier.position(),
171 pos,
172 ))
173 }
174 } else {
175 Err(ContinuityError::PriorPositionNotFound)
176 }
177 }
178
179 /// Returns the range of positions observed by this bridge.
180 pub fn position_range(&self) -> Range<Position> {
181 Range {
182 start: self.prior_position.unwrap_or_else(|| Position::from(0)),
183 end: self.position() + 1,
184 }
185 }
186}
187
188impl<'a, H: Hashable + Clone + Ord + 'a> MerkleBridge<H> {
189 /// Constructs a new bridge to follow this one. If `mark_current_leaf` is true, the successor
190 /// will track the information necessary to create a witness for the leaf most
191 /// recently appended to this bridge's frontier.
192 #[must_use]
193 pub fn successor(&self, track_current_leaf: bool) -> Self {
194 let mut result = Self {
195 prior_position: Some(self.frontier.position()),
196 tracking: self.tracking.clone(),
197 ommers: BTreeMap::new(),
198 frontier: self.frontier.clone(),
199 };
200
201 if track_current_leaf {
202 result.track_current_leaf();
203 }
204
205 result
206 }
207
208 fn track_current_leaf(&mut self) {
209 self.tracking
210 .insert(Address::from(self.frontier.position()).current_incomplete());
211 }
212
213 /// Advances this bridge's frontier by appending the specified node,
214 /// and updates any auth path ommers being tracked if necessary.
215 pub fn append(&mut self, value: H) {
216 self.frontier.append(value);
217
218 let mut found = vec![];
219 for address in self.tracking.iter() {
220 // We know that there will only ever be one address that we're
221 // tracking at a given level, because as soon as we find a
222 // value for the sibling of the address we're tracking, we
223 // remove the tracked address and replace it the next parent
224 // of that address for which we need to find a sibling.
225 if self
226 .frontier()
227 .position()
228 .is_complete_subtree(address.level())
229 {
230 let digest = self.frontier.root(Some(address.level()));
231 self.ommers.insert(address.sibling(), digest);
232 found.push(*address);
233 }
234 }
235
236 for address in found {
237 self.tracking.remove(&address);
238
239 // The address of the next incomplete parent note for which
240 // we need to find a sibling.
241 let parent = address.next_incomplete_parent();
242 assert!(!self.ommers.contains_key(&parent));
243 self.tracking.insert(parent);
244 }
245 }
246
247 /// Returns a single MerkleBridge that contains the aggregate information
248 /// of this bridge and `next`, or None if `next` is not a valid successor
249 /// to this bridge. The resulting Bridge will have the same state as though
250 /// `self` had had every leaf used to construct `next` appended to it
251 /// directly.
252 fn fuse(&self, next: &Self) -> Result<Self, ContinuityError> {
253 self.check_continuity(next)?;
254
255 Ok(Self {
256 prior_position: self.prior_position,
257 tracking: next.tracking.clone(),
258 ommers: self
259 .ommers
260 .iter()
261 .chain(next.ommers.iter())
262 .map(|(k, v)| (*k, v.clone()))
263 .collect(),
264 frontier: next.frontier.clone(),
265 })
266 }
267
268 /// Returns a single MerkleBridge that contains the aggregate information
269 /// of all the provided bridges (discarding internal frontiers) or None
270 /// if the provided iterator is empty. Returns a continuity error if
271 /// any of the bridges are not valid successors to one another.
272 fn fuse_all<T: Iterator<Item = &'a Self>>(
273 mut iter: T,
274 ) -> Result<Option<Self>, ContinuityError> {
275 let mut fused = iter.next().cloned();
276 for next in iter {
277 fused = Some(fused.unwrap().fuse(next)?);
278 }
279 Ok(fused)
280 }
281
282 /// If this bridge contains sufficient auth fragment information, construct an authentication
283 /// path for the specified position by interleaving with values from the prior frontier. This
284 /// method will panic if the position of the prior frontier does not match this bridge's prior
285 /// position.
286 fn witness(
287 &self,
288 depth: u8,
289 prior_frontier: &NonEmptyFrontier<H>,
290 ) -> Result<Vec<H>, WitnessingError> {
291 assert!(Some(prior_frontier.position()) == self.prior_position);
292
293 prior_frontier
294 .witness(depth, |addr| {
295 let r = addr.position_range();
296 if self.frontier.position() < r.start {
297 Some(H::empty_root(addr.level()))
298 } else if r.contains(&self.frontier.position()) {
299 Some(self.frontier.root(Some(addr.level())))
300 } else {
301 // the frontier's position is after the end of the requested
302 // range, so the requested value should exist in a stored
303 // fragment
304 self.ommers.get(&addr).cloned()
305 }
306 })
307 .map_err(WitnessingError::BridgeAddressInvalid)
308 }
309
310 fn retain(&mut self, ommer_addrs: &BTreeSet<Address>) {
311 // Prune away any ommers & tracking addresses we don't need
312 self.tracking
313 .retain(|addr| ommer_addrs.contains(&addr.sibling()));
314 self.ommers.retain(|addr, _| ommer_addrs.contains(addr));
315 }
316}
317
318/// A data structure used to store the information necessary to "rewind" the state of a
319/// [`BridgeTree`] to a particular leaf position.
320///
321/// This is needed because the [`BridgeTree::marked_indices`] map is a cache of information that
322/// crosses [`MerkleBridge`] boundaries, and so it is not sufficient to just truncate the list of
323/// bridges; instead, we use [`Checkpoint`] values to be able to rapidly restore the cache to its
324/// previous state.
325#[derive(Clone, Debug, PartialEq, Eq)]
326pub struct Checkpoint<C> {
327 /// The unique identifier for this checkpoint.
328 id: C,
329 /// The number of bridges that will be retained in a rewind.
330 bridges_len: usize,
331 /// A set of the positions that have been marked during the period that this
332 /// checkpoint is the current checkpoint.
333 marked: BTreeSet<Position>,
334 /// When a mark is forgotten, we add it to the checkpoint's forgotten set but
335 /// don't immediately remove it from the `saved` map; that removal occurs when
336 /// the checkpoint is eventually dropped.
337 forgotten: BTreeSet<Position>,
338}
339
340impl<C> Checkpoint<C> {
341 /// Creates a new checkpoint from its constituent parts.
342 pub fn from_parts(
343 id: C,
344 bridges_len: usize,
345 marked: BTreeSet<Position>,
346 forgotten: BTreeSet<Position>,
347 ) -> Self {
348 Self {
349 id,
350 bridges_len,
351 marked,
352 forgotten,
353 }
354 }
355
356 /// Creates a new empty checkpoint for the specified [`BridgeTree`] state.
357 pub fn at_length(bridges_len: usize, id: C) -> Self {
358 Checkpoint {
359 id,
360 bridges_len,
361 marked: BTreeSet::new(),
362 forgotten: BTreeSet::new(),
363 }
364 }
365
366 /// The unique identifier for the checkpoint.
367 pub fn id(&self) -> &C {
368 &self.id
369 }
370
371 /// Returns the length of the [`BridgeTree::prior_bridges`] vector of the [`BridgeTree`] to
372 /// which this checkpoint refers.
373 ///
374 /// This is the number of bridges that will be retained in the event of a rewind to this
375 /// checkpoint.
376 pub fn bridges_len(&self) -> usize {
377 self.bridges_len
378 }
379
380 /// Returns a set of the positions that have been marked during the period that this
381 /// checkpoint is the current checkpoint.
382 pub fn marked(&self) -> &BTreeSet<Position> {
383 &self.marked
384 }
385
386 /// Returns the set of previously-marked positions that have had their marks removed
387 /// during the period that this checkpoint is the current checkpoint.
388 pub fn forgotten(&self) -> &BTreeSet<Position> {
389 &self.forgotten
390 }
391
392 // A private convenience method that returns the root of the bridge corresponding to
393 // this checkpoint at a specified depth, given the slice of bridges from which this checkpoint
394 // was derived.
395 fn root<H>(&self, bridges: &[MerkleBridge<H>], level: Level) -> H
396 where
397 H: Hashable + Clone + Ord,
398 {
399 if self.bridges_len == 0 {
400 H::empty_root(level)
401 } else {
402 bridges[self.bridges_len - 1].frontier().root(Some(level))
403 }
404 }
405
406 // A private convenience method that returns the position of the bridge corresponding
407 // to this checkpoint, if the checkpoint is not for the empty bridge.
408 fn position<H: Ord>(&self, bridges: &[MerkleBridge<H>]) -> Option<Position> {
409 if self.bridges_len == 0 {
410 None
411 } else {
412 Some(bridges[self.bridges_len - 1].position())
413 }
414 }
415
416 // A private method that rewrites the indices of each forgotten marked record
417 // using the specified rewrite function. Used during garbage collection.
418 fn rewrite_indices<F: Fn(usize) -> usize>(&mut self, f: F) {
419 self.bridges_len = f(self.bridges_len);
420 }
421}
422
423/// A sparse representation of a Merkle tree with linear appending of leaves that contains enough
424/// information to produce a witness for any `mark`ed leaf.
425#[derive(Clone, PartialEq, Eq)]
426pub struct BridgeTree<H, C, const DEPTH: u8> {
427 /// The ordered list of Merkle bridges representing the history
428 /// of the tree. There will be one bridge for each saved leaf.
429 prior_bridges: Vec<MerkleBridge<H>>,
430 /// The current (mutable) bridge at the tip of the tree.
431 current_bridge: Option<MerkleBridge<H>>,
432 /// A map from positions for which we wish to be able to compute a
433 /// witness to index in the bridges vector.
434 saved: BTreeMap<Position, usize>,
435 /// A deque of bridge indices to which it's possible to rewind directly.
436 /// This deque must be maintained to have a minimum size of 1 and a maximum
437 /// size of `max_checkpoints` in order to correctly maintain mark & rewind
438 /// semantics.
439 checkpoints: VecDeque<Checkpoint<C>>,
440 /// The maximum number of checkpoints to retain. If this number is
441 /// exceeded, the oldest checkpoint will be dropped when creating
442 /// a new checkpoint.
443 max_checkpoints: usize,
444}
445
446impl<H: Debug, C: Debug, const DEPTH: u8> Debug for BridgeTree<H, C, DEPTH> {
447 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
448 write!(
449 f,
450 "BridgeTree {{\n depth: {:?},\n prior_bridges: {:?},\n current_bridge: {:?},\n saved: {:?},\n checkpoints: {:?},\n max_checkpoints: {:?}\n}}",
451 DEPTH, self.prior_bridges, self.current_bridge, self.saved, self.checkpoints, self.max_checkpoints
452 )
453 }
454}
455
456/// Errors that can appear when validating the internal consistency of a `[BridgeTree]`
457/// value when constructing a tree from its constituent parts.
458#[derive(Debug, Clone, PartialEq, Eq)]
459pub enum BridgeTreeError {
460 IncorrectIncompleteIndex,
461 InvalidMarkIndex(usize),
462 PositionMismatch { expected: Position, found: Position },
463 InvalidSavePoints,
464 Discontinuity(ContinuityError),
465 CheckpointMismatch,
466}
467
468impl<H, C, const DEPTH: u8> BridgeTree<H, C, DEPTH> {
469 /// Construct an empty BridgeTree value with the specified maximum number of checkpoints.
470 ///
471 /// Panics if `max_checkpoints < 1` because mark/rewind logic depends upon the presence
472 /// of checkpoints to function.
473 pub fn new(max_checkpoints: usize) -> Self {
474 assert!(max_checkpoints >= 1);
475 Self {
476 prior_bridges: vec![],
477 current_bridge: None,
478 saved: BTreeMap::new(),
479 checkpoints: VecDeque::new(),
480 max_checkpoints,
481 }
482 }
483
484 /// Removes the oldest checkpoint if there are more than `max_checkpoints`. Returns true if
485 /// successful and false if there are not enough checkpoints.
486 fn drop_oldest_checkpoint(&mut self) -> bool {
487 if self.checkpoints.len() > self.max_checkpoints {
488 let c = self
489 .checkpoints
490 .pop_front()
491 .expect("Checkpoints deque is known to be non-empty.");
492 for pos in c.forgotten.iter() {
493 self.saved.remove(pos);
494 }
495 true
496 } else {
497 false
498 }
499 }
500
501 /// Returns the prior bridges that make up this tree
502 pub fn prior_bridges(&self) -> &[MerkleBridge<H>] {
503 &self.prior_bridges
504 }
505
506 /// Returns the current bridge at the tip of this tree
507 pub fn current_bridge(&self) -> &Option<MerkleBridge<H>> {
508 &self.current_bridge
509 }
510
511 /// Returns the map from leaf positions that have been marked to the index of
512 /// the bridge whose tip is at that position in this tree's list of bridges.
513 pub fn marked_indices(&self) -> &BTreeMap<Position, usize> {
514 &self.saved
515 }
516
517 /// Returns the checkpoints to which this tree may be rewound.
518 pub fn checkpoints(&self) -> &VecDeque<Checkpoint<C>> {
519 &self.checkpoints
520 }
521
522 /// Returns the maximum number of checkpoints that will be maintained
523 /// by the data structure. When this number of checkpoints is exceeded,
524 /// the oldest checkpoints are discarded when creating new checkpoints.
525 pub fn max_checkpoints(&self) -> usize {
526 self.max_checkpoints
527 }
528
529 /// Returns the bridge's frontier.
530 pub fn frontier(&self) -> Option<&NonEmptyFrontier<H>> {
531 self.current_bridge.as_ref().map(|b| b.frontier())
532 }
533}
534
535impl<H: Hashable + Clone + Ord, C: Clone + Ord, const DEPTH: u8> BridgeTree<H, C, DEPTH> {
536 /// Construct a new BridgeTree that will start recording changes from the state of
537 /// the specified frontier.
538 pub fn from_frontier(max_checkpoints: usize, frontier: NonEmptyFrontier<H>) -> Self {
539 Self {
540 prior_bridges: vec![],
541 current_bridge: Some(MerkleBridge::from_parts(
542 None,
543 BTreeSet::new(),
544 BTreeMap::new(),
545 frontier,
546 )),
547 saved: BTreeMap::new(),
548 checkpoints: VecDeque::new(),
549 max_checkpoints,
550 }
551 }
552
553 /// Construct a new BridgeTree from its constituent parts, checking for internal
554 /// consistency.
555 pub fn from_parts(
556 prior_bridges: Vec<MerkleBridge<H>>,
557 current_bridge: Option<MerkleBridge<H>>,
558 saved: BTreeMap<Position, usize>,
559 checkpoints: VecDeque<Checkpoint<C>>,
560 max_checkpoints: usize,
561 ) -> Result<Self, BridgeTreeError> {
562 Self::check_consistency_internal(
563 &prior_bridges,
564 ¤t_bridge,
565 &saved,
566 &checkpoints,
567 max_checkpoints,
568 )?;
569 Ok(BridgeTree {
570 prior_bridges,
571 current_bridge,
572 saved,
573 checkpoints,
574 max_checkpoints,
575 })
576 }
577
578 fn check_consistency(&self) -> Result<(), BridgeTreeError> {
579 Self::check_consistency_internal(
580 &self.prior_bridges,
581 &self.current_bridge,
582 &self.saved,
583 &self.checkpoints,
584 self.max_checkpoints,
585 )
586 }
587
588 fn check_consistency_internal(
589 prior_bridges: &[MerkleBridge<H>],
590 current_bridge: &Option<MerkleBridge<H>>,
591 saved: &BTreeMap<Position, usize>,
592 checkpoints: &VecDeque<Checkpoint<C>>,
593 max_checkpoints: usize,
594 ) -> Result<(), BridgeTreeError> {
595 // check that saved values correspond to bridges
596 for (pos, i) in saved {
597 if i >= &prior_bridges.len() {
598 return Err(BridgeTreeError::InvalidMarkIndex(*i));
599 }
600 let found = prior_bridges[*i].position();
601 if &found != pos {
602 return Err(BridgeTreeError::PositionMismatch {
603 expected: *pos,
604 found,
605 });
606 }
607 }
608
609 if checkpoints.len() > max_checkpoints
610 || checkpoints
611 .iter()
612 .any(|c| c.bridges_len > prior_bridges.len())
613 {
614 return Err(BridgeTreeError::CheckpointMismatch);
615 }
616
617 for (prev, next) in prior_bridges.iter().zip(prior_bridges.iter().skip(1)) {
618 prev.check_continuity(next)
619 .map_err(BridgeTreeError::Discontinuity)?;
620 }
621
622 if let Some((prev, next)) = prior_bridges.last().zip(current_bridge.as_ref()) {
623 prev.check_continuity(next)
624 .map_err(BridgeTreeError::Discontinuity)?;
625 }
626
627 Ok(())
628 }
629
630 /// Appends a new value to the tree at the next available slot.
631 /// Returns true if successful and false if the tree would exceed
632 /// the maximum allowed depth.
633 pub fn append(&mut self, value: H) -> bool {
634 if let Some(bridge) = self.current_bridge.as_mut() {
635 if bridge
636 .frontier
637 .position()
638 .is_complete_subtree(Level::from(DEPTH))
639 {
640 false
641 } else {
642 bridge.append(value);
643 true
644 }
645 } else {
646 self.current_bridge = Some(MerkleBridge::new(value));
647 true
648 }
649 }
650
651 /// Obtains the root of the Merkle tree at the specified checkpoint depth
652 /// by hashing against empty nodes up to the maximum height of the tree.
653 /// Returns `None` if there are not enough checkpoints available to reach the
654 /// requested checkpoint depth.
655 pub fn root(&self, checkpoint_depth: usize) -> Option<H> {
656 let root_level = Level::from(DEPTH);
657 if checkpoint_depth == 0 {
658 Some(
659 self.current_bridge
660 .as_ref()
661 .map_or(H::empty_root(root_level), |bridge| {
662 bridge.frontier().root(Some(root_level))
663 }),
664 )
665 } else if self.checkpoints.len() >= checkpoint_depth {
666 let checkpoint_idx = self.checkpoints.len() - checkpoint_depth;
667 self.checkpoints
668 .get(checkpoint_idx)
669 .map(|c| c.root(&self.prior_bridges, root_level))
670 } else {
671 None
672 }
673 }
674
675 /// Returns the most recently appended leaf value.
676 pub fn current_position(&self) -> Option<Position> {
677 self.current_bridge.as_ref().map(|b| b.position())
678 }
679
680 /// Returns the most recently appended leaf value.
681 pub fn current_leaf(&self) -> Option<&H> {
682 self.current_bridge.as_ref().map(|b| b.current_leaf())
683 }
684
685 /// Marks the current leaf as one for which we're interested in producing a witness.
686 ///
687 /// Returns an optional value containing the current position if successful or if the current
688 /// value was already marked, or None if the tree is empty.
689 pub fn mark(&mut self) -> Option<Position> {
690 match self.current_bridge.take() {
691 Some(mut cur_b) => {
692 let pos = cur_b.position();
693 // If the latest bridge is a newly created checkpoint, the last prior
694 // bridge will have the same position and all we need to do is mark
695 // the checkpointed leaf as being saved.
696 if self
697 .prior_bridges
698 .last()
699 .map_or(false, |prior_b| prior_b.position() == cur_b.position())
700 {
701 // the current bridge has not been advanced, so we just need to make
702 // sure that we have are tracking the marked leaf
703 cur_b.track_current_leaf();
704 self.current_bridge = Some(cur_b);
705 } else {
706 // the successor(true) call will ensure that the marked leaf is tracked
707 let successor = cur_b.successor(true);
708 self.prior_bridges.push(cur_b);
709 self.current_bridge = Some(successor);
710 }
711
712 // mark the position as having been marked in the current checkpoint
713 if let std::collections::btree_map::Entry::Vacant(e) = self.saved.entry(pos) {
714 if let Some(c) = self.checkpoints.back_mut() {
715 c.marked.insert(pos);
716 }
717 e.insert(self.prior_bridges.len() - 1);
718 }
719
720 Some(pos)
721 }
722 None => None,
723 }
724 }
725
726 /// Return a set of all the positions for which we have marked.
727 pub fn marked_positions(&self) -> BTreeSet<Position> {
728 self.saved.keys().cloned().collect()
729 }
730
731 /// Returns the leaf at the specified position if the tree can produce
732 /// a witness for it.
733 pub fn get_marked_leaf(&self, position: Position) -> Option<&H> {
734 self.saved
735 .get(&position)
736 .and_then(|idx| self.prior_bridges.get(*idx).map(|b| b.current_leaf()))
737 }
738
739 /// Marks the value at the specified position as a value we're no longer
740 /// interested in maintaining a mark for. Returns true if successful and
741 /// false if we were already not maintaining a mark at this position.
742 pub fn remove_mark(&mut self, position: Position) -> bool {
743 if self.saved.contains_key(&position) {
744 if let Some(c) = self.checkpoints.back_mut() {
745 c.forgotten.insert(position);
746 } else {
747 self.saved.remove(&position);
748 }
749 true
750 } else {
751 false
752 }
753 }
754
755 /// Creates a new checkpoint for the current tree state, with the given identifier.
756 ///
757 /// It is valid to have multiple checkpoints for the same tree state, and each `rewind` call
758 /// will remove a single checkpoint. Successive checkpoint identifiers must always be provided
759 /// in increasing order.
760 pub fn checkpoint(&mut self, id: C) -> bool {
761 if Some(&id) > self.checkpoints.back().map(|c| &c.id) {
762 match self.current_bridge.take() {
763 Some(cur_b) => {
764 // Do not create a duplicate bridge
765 if self
766 .prior_bridges
767 .last()
768 .map_or(false, |pb| pb.position() == cur_b.position())
769 {
770 self.current_bridge = Some(cur_b);
771 } else {
772 self.current_bridge = Some(cur_b.successor(false));
773 self.prior_bridges.push(cur_b);
774 }
775
776 self.checkpoints
777 .push_back(Checkpoint::at_length(self.prior_bridges.len(), id));
778 }
779 None => {
780 self.checkpoints.push_back(Checkpoint::at_length(0, id));
781 }
782 }
783
784 if self.checkpoints.len() > self.max_checkpoints {
785 self.drop_oldest_checkpoint();
786 }
787
788 true
789 } else {
790 false
791 }
792 }
793
794 /// Rewinds the tree state to the previous checkpoint, and then removes
795 /// that checkpoint record. If there are multiple checkpoints at a given
796 /// tree state, the tree state will not be altered until all checkpoints
797 /// at that tree state have been removed using `rewind`. This function
798 /// return false and leave the tree unmodified if no checkpoints exist.
799 pub fn rewind(&mut self) -> bool {
800 if let Some(c) = self.checkpoints.pop_back() {
801 // Remove marks for positions that were marked during the lifetime of this checkpoint.
802 for pos in c.marked {
803 self.saved.remove(&pos);
804 }
805
806 self.prior_bridges.truncate(c.bridges_len);
807 self.current_bridge = self
808 .prior_bridges
809 .last()
810 .map(|b| b.successor(self.saved.contains_key(&b.position())));
811 true
812 } else {
813 false
814 }
815 }
816
817 /// Obtains a witness for the value at the specified leaf position, as of the tree state at the
818 /// given checkpoint depth. Returns `None` if there is no witness information for the requested
819 /// position or if no checkpoint is available at the specified depth.
820 pub fn witness(
821 &self,
822 position: Position,
823 checkpoint_depth: usize,
824 ) -> Result<Vec<H>, WitnessingError> {
825 #[derive(Debug)]
826 enum AuthBase<'a, C> {
827 Current,
828 Checkpoint(usize, &'a Checkpoint<C>),
829 }
830
831 // Find the earliest checkpoint having a matching root, or the current
832 // root if it matches and there is no earlier matching checkpoint.
833 let auth_base = if checkpoint_depth == 0 {
834 Ok(AuthBase::Current)
835 } else if self.checkpoints.len() >= checkpoint_depth {
836 let c_idx = self.checkpoints.len() - checkpoint_depth;
837 if self
838 .checkpoints
839 .iter()
840 .skip(c_idx)
841 .take_while(|c| {
842 c.position(&self.prior_bridges)
843 .iter()
844 .any(|p| p <= &position)
845 })
846 .any(|c| c.marked.contains(&position))
847 {
848 // The mark had not yet been established at the point the checkpoint was
849 // created, so we can't treat it as marked.
850 Err(WitnessingError::PositionNotMarked(position))
851 } else {
852 Ok(AuthBase::Checkpoint(c_idx, &self.checkpoints[c_idx]))
853 }
854 } else {
855 Err(WitnessingError::CheckpointInvalid)
856 }?;
857
858 let saved_idx = self
859 .saved
860 .get(&position)
861 .ok_or(WitnessingError::PositionNotMarked(position))?;
862
863 let prior_frontier = &self.prior_bridges[*saved_idx].frontier;
864
865 // Fuse the following bridges to obtain a bridge that has all
866 // of the data to the right of the selected value in the tree,
867 // up to the specified checkpoint depth.
868 let fuse_from = saved_idx + 1;
869 let successor = match auth_base {
870 AuthBase::Current => {
871 // fuse all the way up to the current tip
872 MerkleBridge::fuse_all(
873 self.prior_bridges[fuse_from..]
874 .iter()
875 .chain(&self.current_bridge),
876 )
877 .map(|fused| fused.unwrap()) // safe as the iterator being fused is nonempty
878 .map_err(WitnessingError::BridgeFusionError)
879 }
880 AuthBase::Checkpoint(_, checkpoint) if fuse_from < checkpoint.bridges_len => {
881 // fuse from the provided checkpoint
882 MerkleBridge::fuse_all(self.prior_bridges[fuse_from..checkpoint.bridges_len].iter())
883 .map(|fused| fused.unwrap()) // safe as the iterator being fused is nonempty
884 .map_err(WitnessingError::BridgeFusionError)
885 }
886 AuthBase::Checkpoint(_, checkpoint) if fuse_from == checkpoint.bridges_len => {
887 // The successor bridge should just be the empty successor to the
888 // checkpointed bridge.
889 if checkpoint.bridges_len > 0 {
890 Ok(self.prior_bridges[checkpoint.bridges_len - 1].successor(false))
891 } else {
892 Err(WitnessingError::CheckpointInvalid)
893 }
894 }
895 AuthBase::Checkpoint(_, checkpoint) => {
896 // if the saved index is after the checkpoint, we can't generate
897 // an auth path
898 Err(WitnessingError::CheckpointTooDeep(
899 fuse_from - checkpoint.bridges_len,
900 ))
901 }
902 }?;
903
904 successor.witness(DEPTH, prior_frontier)
905 }
906
907 /// Remove state from the tree that no longer needs to be maintained
908 /// because it is associated with checkpoints or marks that
909 /// have been removed from the tree at positions deeper than those
910 /// reachable by calls to `rewind`.
911 pub fn garbage_collect(&mut self) {
912 // Only garbage collect once we have more bridges than the maximum number of
913 // checkpoints; we cannot remove information that we might need to restore in
914 // a rewind.
915 if self.checkpoints.len() == self.max_checkpoints {
916 let gc_len = self.checkpoints.front().unwrap().bridges_len;
917 let mut cur: Option<MerkleBridge<H>> = None;
918 let mut merged = 0;
919 let mut ommer_addrs: BTreeSet<Address> = BTreeSet::new();
920 for (i, next_bridge) in std::mem::take(&mut self.prior_bridges)
921 .into_iter()
922 .enumerate()
923 {
924 if let Some(cur_bridge) = cur {
925 let pos = cur_bridge.position();
926 let mut new_cur = if self.saved.contains_key(&pos) || i > gc_len {
927 // We need to remember cur_bridge; update its save index & put next_bridge
928 // on the chopping block
929 if let Some(idx) = self.saved.get_mut(&pos) {
930 *idx -= merged;
931 }
932
933 // Add the elements of the auth path to the set of addresses we should
934 // continue to track and retain information for
935 for (addr, source) in cur_bridge
936 .frontier
937 .position()
938 .witness_addrs(Level::from(DEPTH))
939 {
940 if source == Source::Future {
941 ommer_addrs.insert(addr);
942 }
943 }
944
945 self.prior_bridges.push(cur_bridge);
946 next_bridge
947 } else {
948 // We can fuse these bridges together because we don't need to
949 // remember next_bridge.
950 merged += 1;
951 cur_bridge.fuse(&next_bridge).unwrap()
952 };
953
954 new_cur.retain(&ommer_addrs);
955 cur = Some(new_cur);
956 } else {
957 // this case will only occur for the first bridge
958 cur = Some(next_bridge);
959 }
960 }
961
962 // unwrap is safe because we know that prior_bridges was nonempty.
963 if let Some(last_bridge) = cur {
964 if let Some(idx) = self.saved.get_mut(&last_bridge.position()) {
965 *idx -= merged;
966 }
967 self.prior_bridges.push(last_bridge);
968 }
969
970 for c in self.checkpoints.iter_mut() {
971 c.rewrite_indices(|idx| idx - merged);
972 }
973 }
974 if let Err(e) = self.check_consistency() {
975 panic!(
976 "Consistency check failed after garbage collection with {:?}",
977 e
978 );
979 }
980 }
981}
982
983#[cfg(test)]
984mod tests {
985 use proptest::prelude::*;
986 use std::fmt::Debug;
987
988 use super::*;
989 use incrementalmerkletree::Hashable;
990 use incrementalmerkletree_testing::{
991 self as testing, apply_operation, arb_operation, check_checkpoint_rewind, check_operations,
992 check_remove_mark, check_rewind_remove_mark, check_root_hashes, check_witnesses,
993 complete_tree::CompleteTree, CombinedTree, SipHashable,
994 };
995
996 impl<H: Hashable + Clone + Ord, const DEPTH: u8> testing::Tree<H, usize>
997 for BridgeTree<H, usize, DEPTH>
998 {
999 fn append(&mut self, value: H, retention: Retention<usize>) -> bool {
1000 let appended = BridgeTree::append(self, value);
1001 if appended {
1002 if retention.is_marked() {
1003 BridgeTree::mark(self);
1004 }
1005 if let Retention::Checkpoint { id, .. } = retention {
1006 BridgeTree::checkpoint(self, id);
1007 }
1008 }
1009 appended
1010 }
1011
1012 fn depth(&self) -> u8 {
1013 DEPTH
1014 }
1015
1016 fn current_position(&self) -> Option<Position> {
1017 BridgeTree::current_position(self)
1018 }
1019
1020 fn get_marked_leaf(&self, position: Position) -> Option<H> {
1021 BridgeTree::get_marked_leaf(self, position).cloned()
1022 }
1023
1024 fn marked_positions(&self) -> BTreeSet<Position> {
1025 BridgeTree::marked_positions(self)
1026 }
1027
1028 fn root(&self, checkpoint_depth: usize) -> Option<H> {
1029 BridgeTree::root(self, checkpoint_depth)
1030 }
1031
1032 fn witness(&self, position: Position, checkpoint_depth: usize) -> Option<Vec<H>> {
1033 BridgeTree::witness(self, position, checkpoint_depth).ok()
1034 }
1035
1036 fn remove_mark(&mut self, position: Position) -> bool {
1037 BridgeTree::remove_mark(self, position)
1038 }
1039
1040 fn checkpoint(&mut self, id: usize) -> bool {
1041 BridgeTree::checkpoint(self, id)
1042 }
1043
1044 fn rewind(&mut self) -> bool {
1045 BridgeTree::rewind(self)
1046 }
1047 }
1048
1049 #[test]
1050 fn tree_depth() {
1051 let mut tree = BridgeTree::<String, usize, 3>::new(100);
1052 for c in 'a'..'i' {
1053 assert!(tree.append(c.to_string()))
1054 }
1055 assert!(!tree.append('i'.to_string()));
1056 }
1057
1058 fn check_garbage_collect<H: Hashable + Clone + Ord + Debug, const DEPTH: u8>(
1059 mut tree: BridgeTree<H, usize, DEPTH>,
1060 ) {
1061 // Add checkpoints until we're sure everything that can be gc'ed will be gc'ed
1062 for i in 0..tree.max_checkpoints {
1063 tree.checkpoint(i + 1);
1064 }
1065
1066 let mut tree_mut = tree.clone();
1067 tree_mut.garbage_collect();
1068
1069 for pos in tree.saved.keys() {
1070 assert_eq!(tree.witness(*pos, 0), tree_mut.witness(*pos, 0));
1071 }
1072 }
1073
1074 fn arb_bridgetree<G: Strategy + Clone>(
1075 item_gen: G,
1076 max_count: usize,
1077 ) -> impl Strategy<Value = BridgeTree<G::Value, usize, 8>>
1078 where
1079 G::Value: Hashable + Clone + Ord + Debug + 'static,
1080 {
1081 let pos_gen = (0..max_count).prop_map(|p| Position::try_from(p).unwrap());
1082 proptest::collection::vec(arb_operation(item_gen, pos_gen), 0..max_count).prop_map(|ops| {
1083 let mut tree: BridgeTree<G::Value, usize, 8> = BridgeTree::new(10);
1084 for (i, op) in ops.into_iter().enumerate() {
1085 apply_operation(&mut tree, op.map_checkpoint_id(|_| i));
1086 }
1087 tree
1088 })
1089 }
1090
1091 proptest! {
1092 #[test]
1093 fn bridgetree_from_parts(
1094 tree in arb_bridgetree((97u8..123).prop_map(|c| char::from(c).to_string()), 100)
1095 ) {
1096 assert_eq!(
1097 BridgeTree::from_parts(
1098 tree.prior_bridges.clone(),
1099 tree.current_bridge.clone(),
1100 tree.saved.clone(),
1101 tree.checkpoints.clone(),
1102 tree.max_checkpoints
1103 ),
1104 Ok(tree),
1105 );
1106 }
1107
1108 #[test]
1109 fn prop_garbage_collect(
1110 tree in arb_bridgetree((97u8..123).prop_map(|c| char::from(c).to_string()), 100)
1111 ) {
1112 check_garbage_collect(tree);
1113 }
1114 }
1115
1116 #[test]
1117 fn root_hashes() {
1118 check_root_hashes(BridgeTree::<String, usize, 4>::new);
1119 }
1120
1121 #[test]
1122 fn witness() {
1123 check_witnesses(BridgeTree::<String, usize, 4>::new);
1124 }
1125
1126 #[test]
1127 fn checkpoint_rewind() {
1128 check_checkpoint_rewind(|max_checkpoints| {
1129 BridgeTree::<String, usize, 4>::new(max_checkpoints)
1130 });
1131 }
1132
1133 #[test]
1134 fn rewind_remove_mark() {
1135 check_rewind_remove_mark(|max_checkpoints| {
1136 BridgeTree::<String, usize, 4>::new(max_checkpoints)
1137 });
1138 }
1139
1140 #[test]
1141 fn garbage_collect() {
1142 let mut tree: BridgeTree<String, usize, 7> = BridgeTree::new(1000);
1143 let empty_root = tree.root(0);
1144 tree.append("a".to_string());
1145 for i in 0..100 {
1146 tree.checkpoint(i + 1);
1147 }
1148 tree.garbage_collect();
1149 assert!(tree.root(0) != empty_root);
1150 tree.rewind();
1151 assert!(tree.root(0) != empty_root);
1152
1153 let mut t = BridgeTree::<String, usize, 7>::new(10);
1154 let mut to_unmark = vec![];
1155 let mut has_witness = vec![];
1156 for i in 0u64..100 {
1157 let elem: String = format!("{},", i);
1158 assert!(t.append(elem), "Append should succeed.");
1159 if i % 5 == 0 {
1160 t.checkpoint(usize::try_from(i).unwrap() + 1);
1161 }
1162 if i % 7 == 0 {
1163 t.mark();
1164 if i > 0 && i % 2 == 0 {
1165 to_unmark.push(Position::from(i));
1166 } else {
1167 has_witness.push(Position::from(i));
1168 }
1169 }
1170 if i % 11 == 0 && !to_unmark.is_empty() {
1171 let pos = to_unmark.remove(0);
1172 t.remove_mark(pos);
1173 }
1174 }
1175 // 32 = 20 (checkpointed) + 14 (marked) - 2 (marked & checkpointed)
1176 assert_eq!(t.prior_bridges().len(), 20 + 14 - 2);
1177 let witness = has_witness
1178 .iter()
1179 .map(|pos| match t.witness(*pos, 0) {
1180 Ok(path) => path,
1181 Err(e) => panic!("Failed to get auth path: {:?}", e),
1182 })
1183 .collect::<Vec<_>>();
1184 t.garbage_collect();
1185 // 20 = 32 - 10 (removed checkpoints) + 1 (not removed due to mark) - 3 (removed marks)
1186 assert_eq!(t.prior_bridges().len(), 32 - 10 + 1 - 3);
1187 let retained_witness = has_witness
1188 .iter()
1189 .map(|pos| t.witness(*pos, 0).expect("Must be able to get auth path"))
1190 .collect::<Vec<_>>();
1191 assert_eq!(witness, retained_witness);
1192 }
1193
1194 // Combined tree tests
1195 fn new_combined_tree<H: Hashable + Clone + Ord + Debug>(
1196 max_checkpoints: usize,
1197 ) -> CombinedTree<H, usize, CompleteTree<H, usize, 4>, BridgeTree<H, usize, 4>> {
1198 CombinedTree::new(
1199 CompleteTree::<H, usize, 4>::new(max_checkpoints),
1200 BridgeTree::<H, usize, 4>::new(max_checkpoints),
1201 )
1202 }
1203
1204 #[test]
1205 fn combined_remove_mark() {
1206 check_remove_mark(new_combined_tree);
1207 }
1208
1209 #[test]
1210 fn combined_rewind_remove_mark() {
1211 check_rewind_remove_mark(new_combined_tree);
1212 }
1213
1214 proptest! {
1215 #![proptest_config(ProptestConfig::with_cases(100000))]
1216
1217 #[test]
1218 fn check_randomized_u64_ops(
1219 ops in proptest::collection::vec(
1220 arb_operation(
1221 (0..32u64).prop_map(SipHashable),
1222 (0u64..100).prop_map(Position::from)
1223 ),
1224 1..100
1225 )
1226 ) {
1227 let tree = new_combined_tree(100);
1228 let indexed_ops = ops.iter().enumerate().map(|(i, op)| op.map_checkpoint_id(|_| i + 1)).collect::<Vec<_>>();
1229 check_operations(tree, &indexed_ops)?;
1230 }
1231
1232 #[test]
1233 fn check_randomized_str_ops(
1234 ops in proptest::collection::vec(
1235 arb_operation(
1236 (97u8..123).prop_map(|c| char::from(c).to_string()),
1237 (0u64..100).prop_map(Position::from)
1238 ),
1239 1..100
1240 )
1241 ) {
1242 let tree = new_combined_tree(100);
1243 let indexed_ops = ops.iter().enumerate().map(|(i, op)| op.map_checkpoint_id(|_| i + 1)).collect::<Vec<_>>();
1244 check_operations(tree, &indexed_ops)?;
1245 }
1246 }
1247}