zebra_chain/sprout/tree/
legacy.rs

1//! Sprout serialization legacy code.
2//!
3//! We create a [`LegacyNoteCommitmentTree`] which is a copy of [`NoteCommitmentTree`] but where serialization and
4//! deserialization can be derived.
5//! To do this we create a [`LegacyFrontier`] which is a legacy `Frontier` structure that can be found in [1],
6//! In order to make [`LegacyFrontier`] serializable we also have our own versions of `NonEmptyFrontier` ([`LegacyNonEmptyFrontier`]),
7//! `Leaf`([`LegacyLeaf`]) and `Position`([`LegacyPosition`]) that can be found in [1] or [2].
8//!
9//! Conversions methods to/from [`LegacyNoteCommitmentTree`] to/from [`NoteCommitmentTree`] are defined also in this file.
10//!
11//! [1]: https://github.com/zcash/incrementalmerkletree/blob/incrementalmerkletree-v0.3.1/src/bridgetree.rs
12//! [2]: https://github.com/zcash/incrementalmerkletree/blob/incrementalmerkletree-v0.3.1/src/lib.rs
13
14use incrementalmerkletree::{frontier::Frontier, Position};
15
16use super::{Node, NoteCommitmentTree, Root, MERKLE_DEPTH};
17
18/// A legacy version of [`NoteCommitmentTree`].
19#[derive(Debug, Serialize, Deserialize)]
20#[serde(rename = "NoteCommitmentTree")]
21pub struct LegacyNoteCommitmentTree {
22    inner: LegacyFrontier<Node, MERKLE_DEPTH>,
23    cached_root: std::sync::RwLock<Option<Root>>,
24}
25
26impl From<NoteCommitmentTree> for LegacyNoteCommitmentTree {
27    fn from(nct: NoteCommitmentTree) -> Self {
28        LegacyNoteCommitmentTree {
29            inner: nct.inner.into(),
30            cached_root: nct.cached_root,
31        }
32    }
33}
34
35impl From<LegacyNoteCommitmentTree> for NoteCommitmentTree {
36    fn from(nct: LegacyNoteCommitmentTree) -> Self {
37        NoteCommitmentTree {
38            inner: nct.inner.into(),
39            cached_root: nct.cached_root,
40        }
41    }
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
45#[serde(rename = "Frontier")]
46#[allow(missing_docs)]
47pub struct LegacyFrontier<H, const DEPTH: u8> {
48    frontier: Option<LegacyNonEmptyFrontier<H>>,
49}
50
51impl From<LegacyFrontier<Node, MERKLE_DEPTH>> for Frontier<Node, MERKLE_DEPTH> {
52    fn from(legacy_frontier: LegacyFrontier<Node, MERKLE_DEPTH>) -> Self {
53        if let Some(legacy_frontier_data) = legacy_frontier.frontier {
54            let mut ommers = legacy_frontier_data.ommers;
55            let position = Position::from(
56                u64::try_from(legacy_frontier_data.position.0)
57                    .expect("old `usize` always fits in `u64`"),
58            );
59            let leaf = match legacy_frontier_data.leaf {
60                LegacyLeaf::Left(a) => a,
61                LegacyLeaf::Right(a, b) => {
62                    ommers.insert(0, a);
63                    b
64                }
65            };
66            Frontier::from_parts(
67                position,
68                leaf,
69                ommers,
70            )
71            .expect("We should be able to construct a frontier from parts given legacy frontier is not empty")
72        } else {
73            Frontier::empty()
74        }
75    }
76}
77
78impl From<Frontier<Node, MERKLE_DEPTH>> for LegacyFrontier<Node, MERKLE_DEPTH> {
79    fn from(frontier: Frontier<Node, MERKLE_DEPTH>) -> Self {
80        if let Some(frontier_data) = frontier.value() {
81            let leaf_from_frontier = *frontier_data.leaf();
82            let mut leaf = LegacyLeaf::Left(leaf_from_frontier);
83            let mut ommers = frontier_data.ommers().to_vec();
84            let position = usize::try_from(u64::from(frontier_data.position()))
85                .expect("new position should fit in a `usize`");
86            if frontier_data.position().is_right_child() {
87                let left = ommers.remove(0);
88                leaf = LegacyLeaf::Right(left, leaf_from_frontier);
89            }
90            LegacyFrontier {
91                frontier: Some(LegacyNonEmptyFrontier {
92                    position: LegacyPosition(position),
93                    leaf,
94                    ommers: ommers.to_vec(),
95                }),
96            }
97        } else {
98            LegacyFrontier { frontier: None }
99        }
100    }
101}
102
103#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
104#[serde(rename = "NonEmptyFrontier")]
105struct LegacyNonEmptyFrontier<H> {
106    position: LegacyPosition,
107    leaf: LegacyLeaf<H>,
108    ommers: Vec<H>,
109}
110
111/// A set of leaves of a Merkle tree.
112#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
113#[serde(rename = "Leaf")]
114enum LegacyLeaf<A> {
115    Left(A),
116    Right(A, A),
117}
118
119#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
120#[repr(transparent)]
121struct LegacyPosition(usize);