1use serde::{Deserialize, Serialize};
11
12use crate::hash::{sha256d, Hash32};
13use crate::merkle::merkle_root;
14use crate::transaction::Transaction;
15
16#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
17pub struct BlockHeader {
18 pub version: u32,
19 pub prev_hash: Hash32,
20 pub merkle_root: Hash32,
21 pub state_root: Hash32,
25 pub time: u32,
26 pub bits: u32,
28 pub nonce: [u8; 32],
29 pub solution: Vec<u8>,
32}
33
34fn put_compact_size(out: &mut Vec<u8>, n: u64) {
36 match n {
37 0..=0xfc => out.push(n as u8),
38 0xfd..=0xffff => {
39 out.push(0xfd);
40 out.extend_from_slice(&(n as u16).to_le_bytes());
41 }
42 _ => {
43 out.push(0xfe);
44 out.extend_from_slice(&(n as u32).to_le_bytes());
45 }
46 }
47}
48
49impl BlockHeader {
50 pub fn equihash_input(&self) -> [u8; 108] {
53 let mut out = [0u8; 108];
54 out[0..4].copy_from_slice(&self.version.to_le_bytes());
55 out[4..36].copy_from_slice(&self.prev_hash);
56 out[36..68].copy_from_slice(&self.merkle_root);
57 out[68..100].copy_from_slice(&self.state_root);
58 out[100..104].copy_from_slice(&self.time.to_le_bytes());
59 out[104..108].copy_from_slice(&self.bits.to_le_bytes());
60 out
61 }
62
63 pub fn serialize(&self) -> Vec<u8> {
65 let mut out = Vec::with_capacity(140 + 3 + self.solution.len());
66 out.extend_from_slice(&self.equihash_input());
67 out.extend_from_slice(&self.nonce);
68 put_compact_size(&mut out, self.solution.len() as u64);
69 out.extend_from_slice(&self.solution);
70 out
71 }
72
73 pub fn hash(&self) -> Hash32 {
76 sha256d(&self.serialize())
77 }
78}
79
80#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
81pub struct Block {
82 pub header: BlockHeader,
83 #[serde(default)]
89 pub aux_pow: Option<crate::auxpow::AuxPow>,
90 pub transactions: Vec<Transaction>,
91}
92
93impl Block {
94 pub fn compute_merkle_root(&self) -> Hash32 {
95 let txids: Vec<Hash32> = self.transactions.iter().map(|t| t.txid()).collect();
96 merkle_root(&txids)
97 }
98
99 pub fn serialized_size(&self) -> usize {
100 self.header.serialize().len()
101 + self.aux_pow.as_ref().map(|a| a.serialized_size()).unwrap_or(0)
102 + self.transactions.iter().map(|t| t.serialized_size()).sum::<usize>()
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn header_layout_is_zcash_shaped() {
112 let header = BlockHeader {
113 version: 4,
114 prev_hash: [1; 32],
115 merkle_root: [2; 32],
116 state_root: [0; 32],
117 time: 1_790_000_000,
118 bits: 0x1f07ffff,
119 nonce: [3; 32],
120 solution: vec![0xaa; 1344],
121 };
122 assert_eq!(header.equihash_input().len(), 108);
123 assert_eq!(header.serialize().len(), 140 + 3 + 1344);
125 let mut tampered = header.clone();
126 tampered.nonce[0] ^= 1;
127 assert_ne!(header.hash(), tampered.hash());
128 }
129}