zebra_chain/orchard/tree/
legacy.rs

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