Skip to main content

zcash_history/
entry.rs

1use crate::{EntryKind, EntryLink, Error, MAX_NODE_DATA_SIZE, Version};
2
3/// Max serialized length of entry data.
4pub const MAX_ENTRY_SIZE: usize = MAX_NODE_DATA_SIZE + 9;
5
6/// MMR Entry.
7#[derive(Debug)]
8pub struct Entry<V: Version> {
9    pub(crate) kind: EntryKind,
10    pub(crate) data: V::NodeData,
11}
12
13impl<V: Version> Entry<V> {
14    /// New entry of type node.
15    pub fn new(data: V::NodeData, left: EntryLink, right: EntryLink) -> Self {
16        Entry {
17            kind: EntryKind::Node(left, right),
18            data,
19        }
20    }
21
22    /// Returns the data associated with this node.
23    pub fn data(&self) -> &V::NodeData {
24        &self.data
25    }
26
27    /// Creates a new leaf.
28    pub fn new_leaf(data: V::NodeData) -> Self {
29        Entry {
30            kind: EntryKind::Leaf,
31            data,
32        }
33    }
34
35    /// Returns if is this node complete (has total of 2^N leaves)
36    pub fn complete(&self) -> bool {
37        self.leaf_count().is_power_of_two()
38    }
39
40    /// Number of leaves under this node.
41    ///
42    /// # Panics
43    ///
44    /// Panics if this entry was constructed with a descending height range or
45    /// a range containing more leaves than can be represented by a `u64`.
46    /// Entries produced by [`Self::read`] are validated against these cases.
47    pub fn leaf_count(&self) -> u64 {
48        V::end_height(&self.data)
49            .checked_sub(V::start_height(&self.data))
50            .and_then(|height_diff| height_diff.checked_add(1))
51            .expect("entry height range must contain a representable number of leaves")
52    }
53
54    /// Is this node a leaf.
55    pub fn leaf(&self) -> bool {
56        matches!(self.kind, EntryKind::Leaf)
57    }
58
59    /// Left child
60    pub fn left(&self) -> Result<EntryLink, Error> {
61        match self.kind {
62            EntryKind::Leaf => Err(Error::node_expected()),
63            EntryKind::Node(left, _) => Ok(left),
64        }
65    }
66
67    /// Right child.
68    pub fn right(&self) -> Result<EntryLink, Error> {
69        match self.kind {
70            EntryKind::Leaf => Err(Error::node_expected()),
71            EntryKind::Node(_, right) => Ok(right),
72        }
73    }
74
75    /// Read from byte representation.
76    pub fn read<R: corez::io::Read>(
77        consensus_branch_id: u32,
78        r: &mut R,
79    ) -> corez::io::Result<Self> {
80        let kind = {
81            let mut byte = [0u8; 1];
82            r.read_exact(&mut byte)?;
83            match byte[0] {
84                0 => {
85                    let mut buf = [0u8; 4];
86                    r.read_exact(&mut buf)?;
87                    let left = u32::from_le_bytes(buf);
88                    r.read_exact(&mut buf)?;
89                    let right = u32::from_le_bytes(buf);
90                    EntryKind::Node(EntryLink::Stored(left), EntryLink::Stored(right))
91                }
92                1 => EntryKind::Leaf,
93                _ => return Err(corez::io::Error::from(corez::io::ErrorKind::InvalidData)),
94            }
95        };
96
97        let data = V::read(consensus_branch_id, r)?;
98
99        Ok(Entry { kind, data })
100    }
101
102    /// Write to byte representation.
103    pub fn write<W: corez::io::Write>(&self, w: &mut W) -> corez::io::Result<()> {
104        match self.kind {
105            EntryKind::Node(EntryLink::Stored(left), EntryLink::Stored(right)) => {
106                w.write_all(&[0])?;
107                w.write_all(&left.to_le_bytes())?;
108                w.write_all(&right.to_le_bytes())?;
109            }
110            EntryKind::Leaf => {
111                w.write_all(&[1])?;
112            }
113            _ => {
114                return Err(corez::io::Error::from(corez::io::ErrorKind::InvalidData));
115            }
116        }
117
118        V::write(&self.data, w)?;
119
120        Ok(())
121    }
122
123    /// Convert from byte representation.
124    pub fn from_bytes<T: AsRef<[u8]>>(consensus_branch_id: u32, buf: T) -> corez::io::Result<Self> {
125        let mut cursor = corez::io::Cursor::new(buf);
126        Self::read(consensus_branch_id, &mut cursor)
127    }
128}
129
130impl<V: Version> core::fmt::Display for Entry<V> {
131    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
132        match self.kind {
133            EntryKind::Node(l, r) => write!(f, "node({l}, {r}, ..)"),
134            EntryKind::Leaf => write!(f, "leaf(..)"),
135        }
136    }
137}