zcash_history/
entry.rs

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