1use alloc::vec::Vec;
2
3use crate::{
4 Digest, Felt, Hasher, ZERO,
5 block::BlockNumber,
6 utils::serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
7};
8
9#[derive(Debug, Eq, PartialEq, Clone)]
31pub struct BlockHeader {
32 version: u32,
33 prev_block_commitment: Digest,
34 block_num: BlockNumber,
35 chain_commitment: Digest,
36 account_root: Digest,
37 nullifier_root: Digest,
38 note_root: Digest,
39 tx_commitment: Digest,
40 tx_kernel_commitment: Digest,
41 proof_commitment: Digest,
42 timestamp: u32,
43 sub_commitment: Digest,
44 commitment: Digest,
45}
46
47impl BlockHeader {
48 #[allow(clippy::too_many_arguments)]
50 pub fn new(
51 version: u32,
52 prev_block_commitment: Digest,
53 block_num: BlockNumber,
54 chain_commitment: Digest,
55 account_root: Digest,
56 nullifier_root: Digest,
57 note_root: Digest,
58 tx_commitment: Digest,
59 tx_kernel_commitment: Digest,
60 proof_commitment: Digest,
61 timestamp: u32,
62 ) -> Self {
63 let sub_commitment = Self::compute_sub_commitment(
65 version,
66 prev_block_commitment,
67 chain_commitment,
68 account_root,
69 nullifier_root,
70 tx_commitment,
71 tx_kernel_commitment,
72 proof_commitment,
73 timestamp,
74 block_num,
75 );
76
77 let commitment = Hasher::merge(&[sub_commitment, note_root]);
82
83 Self {
84 version,
85 prev_block_commitment,
86 block_num,
87 chain_commitment,
88 account_root,
89 nullifier_root,
90 note_root,
91 tx_commitment,
92 tx_kernel_commitment,
93 proof_commitment,
94 timestamp,
95 sub_commitment,
96 commitment,
97 }
98 }
99
100 pub fn version(&self) -> u32 {
105 self.version
106 }
107
108 pub fn commitment(&self) -> Digest {
110 self.commitment
111 }
112
113 pub fn sub_commitment(&self) -> Digest {
120 self.sub_commitment
121 }
122
123 pub fn prev_block_commitment(&self) -> Digest {
125 self.prev_block_commitment
126 }
127
128 pub fn block_num(&self) -> BlockNumber {
130 self.block_num
131 }
132
133 pub fn block_epoch(&self) -> u16 {
137 self.block_num.block_epoch()
138 }
139
140 pub fn chain_commitment(&self) -> Digest {
142 self.chain_commitment
143 }
144
145 pub fn account_root(&self) -> Digest {
147 self.account_root
148 }
149
150 pub fn nullifier_root(&self) -> Digest {
152 self.nullifier_root
153 }
154
155 pub fn note_root(&self) -> Digest {
157 self.note_root
158 }
159
160 pub fn tx_commitment(&self) -> Digest {
166 self.tx_commitment
167 }
168
169 pub fn tx_kernel_commitment(&self) -> Digest {
174 self.tx_kernel_commitment
175 }
176
177 pub fn proof_commitment(&self) -> Digest {
179 self.proof_commitment
180 }
181
182 pub fn timestamp(&self) -> u32 {
184 self.timestamp
185 }
186
187 pub fn epoch_block_num(&self) -> BlockNumber {
189 BlockNumber::from_epoch(self.block_epoch())
190 }
191
192 #[allow(clippy::too_many_arguments)]
202 fn compute_sub_commitment(
203 version: u32,
204 prev_block_commitment: Digest,
205 chain_commitment: Digest,
206 account_root: Digest,
207 nullifier_root: Digest,
208 tx_commitment: Digest,
209 tx_kernel_commitment: Digest,
210 proof_commitment: Digest,
211 timestamp: u32,
212 block_num: BlockNumber,
213 ) -> Digest {
214 let mut elements: Vec<Felt> = Vec::with_capacity(32);
215 elements.extend_from_slice(prev_block_commitment.as_elements());
216 elements.extend_from_slice(chain_commitment.as_elements());
217 elements.extend_from_slice(account_root.as_elements());
218 elements.extend_from_slice(nullifier_root.as_elements());
219 elements.extend_from_slice(tx_commitment.as_elements());
220 elements.extend_from_slice(tx_kernel_commitment.as_elements());
221 elements.extend_from_slice(proof_commitment.as_elements());
222 elements.extend([block_num.into(), version.into(), timestamp.into(), ZERO]);
223 Hasher::hash_elements(&elements)
224 }
225}
226
227impl Serializable for BlockHeader {
231 fn write_into<W: ByteWriter>(&self, target: &mut W) {
232 self.version.write_into(target);
233 self.prev_block_commitment.write_into(target);
234 self.block_num.write_into(target);
235 self.chain_commitment.write_into(target);
236 self.account_root.write_into(target);
237 self.nullifier_root.write_into(target);
238 self.note_root.write_into(target);
239 self.tx_commitment.write_into(target);
240 self.tx_kernel_commitment.write_into(target);
241 self.proof_commitment.write_into(target);
242 self.timestamp.write_into(target);
243 }
244}
245
246impl Deserializable for BlockHeader {
247 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
248 let version = source.read()?;
249 let prev_block_commitment = source.read()?;
250 let block_num = source.read()?;
251 let chain_commitment = source.read()?;
252 let account_root = source.read()?;
253 let nullifier_root = source.read()?;
254 let note_root = source.read()?;
255 let tx_commitment = source.read()?;
256 let tx_kernel_commitment = source.read()?;
257 let proof_commitment = source.read()?;
258 let timestamp = source.read()?;
259
260 Ok(Self::new(
261 version,
262 prev_block_commitment,
263 block_num,
264 chain_commitment,
265 account_root,
266 nullifier_root,
267 note_root,
268 tx_commitment,
269 tx_kernel_commitment,
270 proof_commitment,
271 timestamp,
272 ))
273 }
274}
275
276#[cfg(test)]
277mod tests {
278 use vm_core::Word;
279 use winter_rand_utils::rand_array;
280
281 use super::*;
282
283 #[test]
284 fn test_serde() {
285 let chain_commitment: Word = rand_array();
286 let note_root: Word = rand_array();
287 let tx_kernel_commitment: Word = rand_array();
288 let header = BlockHeader::mock(
289 0,
290 Some(chain_commitment.into()),
291 Some(note_root.into()),
292 &[],
293 tx_kernel_commitment.into(),
294 );
295 let serialized = header.to_bytes();
296 let deserialized = BlockHeader::read_from_bytes(&serialized).unwrap();
297
298 assert_eq!(deserialized, header);
299 }
300}