zebra_chain/sapling/tree/
legacy.rs

1//! Sapling 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};
15use serde::Serialize;
16
17use super::{serde_helpers, NoteCommitmentTree, Root, MERKLE_DEPTH};
18
19/// A serializable version of `sapling_crypto::Node`.
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct Node(#[serde(with = "serde_helpers::Node")] pub sapling_crypto::Node);
22
23impl From<sapling_crypto::Node> for Node {
24    fn from(n: sapling_crypto::Node) -> Self {
25        Node(n)
26    }
27}
28
29impl From<Node> for sapling_crypto::Node {
30    fn from(n: Node) -> Self {
31        n.0
32    }
33}
34
35/// A legacy version of [`NoteCommitmentTree`].
36#[derive(Debug, Serialize, Deserialize)]
37#[serde(rename = "NoteCommitmentTree")]
38#[allow(missing_docs)]
39pub struct LegacyNoteCommitmentTree {
40    pub inner: LegacyFrontier<Node, MERKLE_DEPTH>,
41    cached_root: std::sync::RwLock<Option<Root>>,
42}
43
44impl From<NoteCommitmentTree> for LegacyNoteCommitmentTree {
45    fn from(nct: NoteCommitmentTree) -> Self {
46        LegacyNoteCommitmentTree {
47            inner: nct.inner.into(),
48            cached_root: nct.cached_root,
49        }
50    }
51}
52
53impl From<LegacyNoteCommitmentTree> for NoteCommitmentTree {
54    fn from(nct: LegacyNoteCommitmentTree) -> Self {
55        NoteCommitmentTree {
56            inner: nct.inner.into(),
57            cached_root: nct.cached_root,
58        }
59    }
60}
61
62#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
63#[serde(rename = "Frontier")]
64#[allow(missing_docs)]
65pub struct LegacyFrontier<H, const DEPTH: u8> {
66    pub frontier: Option<LegacyNonEmptyFrontier<H>>,
67}
68
69impl From<LegacyFrontier<Node, MERKLE_DEPTH>> for Frontier<sapling_crypto::Node, MERKLE_DEPTH> {
70    fn from(legacy_frontier: LegacyFrontier<Node, MERKLE_DEPTH>) -> Self {
71        if let Some(legacy_frontier_data) = legacy_frontier.frontier {
72            let mut ommers = legacy_frontier_data
73                .ommers
74                .into_iter()
75                .map(|o| o.0)
76                .collect::<Vec<_>>();
77            let position = Position::from(
78                u64::try_from(legacy_frontier_data.position.0)
79                    .expect("old `usize` always fits in `u64`"),
80            );
81            let leaf = match legacy_frontier_data.leaf {
82                LegacyLeaf::Left(a) => a.0,
83                LegacyLeaf::Right(a, b) => {
84                    ommers.insert(0, a.0);
85                    b.0
86                }
87            };
88            Frontier::from_parts(
89                position,
90                leaf,
91                ommers,
92            )
93            .expect("We should be able to construct a frontier from parts given legacy frontier is not empty")
94        } else {
95            Frontier::empty()
96        }
97    }
98}
99
100impl From<Frontier<sapling_crypto::Node, MERKLE_DEPTH>> for LegacyFrontier<Node, MERKLE_DEPTH> {
101    fn from(frontier: Frontier<sapling_crypto::Node, MERKLE_DEPTH>) -> Self {
102        if let Some(frontier_data) = frontier.value() {
103            let leaf_from_frontier = Node(*frontier_data.leaf());
104            let mut leaf = LegacyLeaf::Left(leaf_from_frontier.clone());
105            let mut ommers = frontier_data
106                .ommers()
107                .iter()
108                .map(|o| Node(*o))
109                .collect::<Vec<_>>();
110            let position = usize::try_from(u64::from(frontier_data.position()))
111                .expect("new position should fit in a `usize`");
112            if frontier_data.position().is_right_child() {
113                let left = ommers.remove(0);
114                leaf = LegacyLeaf::Right(left, leaf_from_frontier);
115            }
116            LegacyFrontier {
117                frontier: Some(LegacyNonEmptyFrontier {
118                    position: LegacyPosition(position),
119                    leaf,
120                    ommers: ommers.to_vec(),
121                }),
122            }
123        } else {
124            LegacyFrontier { frontier: None }
125        }
126    }
127}
128
129#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
130#[serde(rename = "NonEmptyFrontier")]
131#[allow(missing_docs)]
132pub struct LegacyNonEmptyFrontier<H> {
133    pub position: LegacyPosition,
134    pub leaf: LegacyLeaf<H>,
135    pub ommers: Vec<H>,
136}
137
138/// A set of leaves of a Merkle tree.
139#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
140#[serde(rename = "Leaf")]
141#[allow(missing_docs)]
142pub enum LegacyLeaf<A> {
143    Left(A),
144    Right(A, A),
145}
146
147#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
148#[repr(transparent)]
149#[allow(missing_docs)]
150pub struct LegacyPosition(pub usize);