Skip to main content

zebra_rpc/methods/
trees.rs

1//! Types and functions for note commitment tree RPCs.
2
3use derive_getters::Getters;
4use derive_new::new;
5use zebra_chain::{
6    block::Hash,
7    block::Height,
8    subtree::{NoteCommitmentSubtreeData, NoteCommitmentSubtreeIndex},
9};
10
11/// A subtree data type that can hold Sapling or Orchard subtree roots.
12pub type SubtreeRpcData = NoteCommitmentSubtreeData<String>;
13
14/// Response to a `z_getsubtreesbyindex` RPC request.
15///
16/// Contains the Sapling or Orchard pool label, the index of the first subtree in the list,
17/// and a list of subtree roots and end heights.
18#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, Getters, new)]
19pub struct GetSubtreesByIndexResponse {
20    /// The shielded pool to which the subtrees belong.
21    //
22    // TODO: consider an enum with a string conversion?
23    pub(crate) pool: String,
24
25    /// The index of the first subtree.
26    #[getter(copy)]
27    pub(crate) start_index: NoteCommitmentSubtreeIndex,
28
29    /// A sequential list of complete subtrees, in `index` order.
30    ///
31    /// The generic subtree root type is a hex-encoded Sapling or Orchard subtree root string.
32    //
33    // TODO: is this needed?
34    //#[serde(skip_serializing_if = "Vec::is_empty")]
35    pub(crate) subtrees: Vec<SubtreeRpcData>,
36}
37
38impl Default for GetSubtreesByIndexResponse {
39    fn default() -> Self {
40        Self {
41            pool: "sapling | orchard".to_string(),
42            start_index: NoteCommitmentSubtreeIndex(u16::default()),
43            subtrees: vec![],
44        }
45    }
46}
47
48/// Response to a `z_gettreestate` RPC request.
49///
50/// Contains hex-encoded Sapling & Orchard note commitment trees and their corresponding
51/// [`struct@Hash`], [`Height`], and block time.
52///
53/// The format of the serialized trees represents `CommitmentTree`s from the crate
54/// `incrementalmerkletree` and not `Frontier`s from the same crate, even though `zebrad`'s
55/// `NoteCommitmentTree`s are implemented using `Frontier`s. Zebra follows the former format to stay
56/// consistent with `zcashd`'s RPCs.
57///
58/// The formats are semantically equivalent. The difference is that in `Frontier`s, the vector of
59/// ommers is dense (we know where the gaps are from the position of the leaf in the overall tree);
60/// whereas in `CommitmentTree`, the vector of ommers is sparse with [`None`] values in the gaps.
61///
62/// The dense format might be used in future RPCs.
63#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, Getters, new)]
64pub struct GetTreestateResponse {
65    /// The block hash corresponding to the treestate, hex-encoded.
66    #[serde(with = "hex")]
67    #[getter(copy)]
68    hash: Hash,
69
70    /// The block height corresponding to the treestate, numeric.
71    #[getter(copy)]
72    height: Height,
73
74    /// Unix time when the block corresponding to the treestate was mined,
75    /// numeric.
76    ///
77    /// UTC seconds since the Unix 1970-01-01 epoch.
78    time: u32,
79
80    /// A treestate containing a Sprout note commitment tree, hex-encoded. Zebra
81    /// does not support returning it; but the field is here to enable parsing
82    /// responses from other implementations.
83    #[serde(skip_serializing_if = "Option::is_none")]
84    sprout: Option<Treestate>,
85
86    /// A treestate containing a Sapling note commitment tree, hex-encoded.
87    sapling: Treestate,
88
89    /// A treestate containing an Orchard note commitment tree, hex-encoded.
90    orchard: Treestate,
91
92    /// A treestate containing an Ironwood note commitment tree, hex-encoded. Only present from
93    /// NU6.3, so that pre-NU6.3 responses are unchanged.
94    #[serde(skip_serializing_if = "Option::is_none")]
95    ironwood: Option<Treestate>,
96}
97
98impl GetTreestateResponse {
99    /// Constructs [`Treestate`] from its constituent parts.
100    #[deprecated(note = "Use `new` instead.")]
101    pub fn from_parts(
102        hash: Hash,
103        height: Height,
104        time: u32,
105        sapling: Option<Vec<u8>>,
106        orchard: Option<Vec<u8>>,
107    ) -> Self {
108        let sapling = Treestate {
109            commitments: Commitments {
110                final_state: sapling,
111                final_root: None,
112            },
113        };
114        let orchard = Treestate {
115            commitments: Commitments {
116                final_state: orchard,
117                final_root: None,
118            },
119        };
120
121        Self {
122            hash,
123            height,
124            time,
125            sprout: None,
126            sapling,
127            orchard,
128            ironwood: None,
129        }
130    }
131
132    /// Returns the contents of ['GetTreeState'].
133    #[deprecated(note = "Use getters instead.")]
134    pub fn into_parts(self) -> (Hash, Height, u32, Option<Vec<u8>>, Option<Vec<u8>>) {
135        (
136            self.hash,
137            self.height,
138            self.time,
139            self.sapling.commitments.final_state,
140            self.orchard.commitments.final_state,
141        )
142    }
143}
144
145impl Default for GetTreestateResponse {
146    fn default() -> Self {
147        Self {
148            hash: Hash([0; 32]),
149            height: Height::MIN,
150            time: Default::default(),
151            sprout: Default::default(),
152            sapling: Default::default(),
153            orchard: Default::default(),
154            ironwood: None,
155        }
156    }
157}
158
159/// A treestate that is included in the [`z_gettreestate`][1] RPC response.
160///
161/// [1]: https://zcash.github.io/rpc/z_gettreestate.html
162#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, Getters, new)]
163pub struct Treestate {
164    /// Contains an Orchard or Sapling serialized note commitment tree,
165    /// hex-encoded.
166    commitments: Commitments,
167}
168
169impl Treestate {
170    /// Returns a reference to the commitments.
171    #[deprecated(note = "Use `commitments()` instead.")]
172    pub fn inner(&self) -> &Commitments {
173        self.commitments()
174    }
175}
176
177impl Default for Treestate {
178    fn default() -> Self {
179        Self {
180            commitments: Commitments {
181                final_root: None,
182                final_state: None,
183            },
184        }
185    }
186}
187
188/// A wrapper that contains either an Orchard or Sapling note commitment tree.
189///
190/// Note that in the original [`z_gettreestate`][1] RPC, [`Commitments`] also
191/// contains the field `finalRoot`. Zebra does *not* use this field.
192///
193/// [1]: https://zcash.github.io/rpc/z_gettreestate.html
194#[serde_with::serde_as]
195#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, Getters, new)]
196pub struct Commitments {
197    /// Orchard or Sapling serialized note commitment tree root, hex-encoded.
198    #[serde_as(as = "Option<serde_with::hex::Hex>")]
199    #[serde(skip_serializing_if = "Option::is_none")]
200    #[serde(rename = "finalRoot")]
201    final_root: Option<Vec<u8>>,
202    /// Orchard or Sapling serialized note commitment tree, hex-encoded.
203    #[serde_as(as = "Option<serde_with::hex::Hex>")]
204    #[serde(skip_serializing_if = "Option::is_none")]
205    #[serde(rename = "finalState")]
206    final_state: Option<Vec<u8>>,
207}
208
209impl Commitments {
210    /// Returns a reference to the optional `final_state`.
211    #[deprecated(note = "Use `final_state()` instead.")]
212    pub fn inner(&self) -> &Option<Vec<u8>> {
213        &self.final_state
214    }
215}