1use crate::transaction::{
6 SerializablePublicKey, SerializableSignature, Transaction, TransactionId,
7};
8use serde::{Deserialize, Serialize};
9use sha2::{Digest, Sha256};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
13pub struct BlockId([u8; 32]);
14
15impl BlockId {
16 pub const GENESIS_PARENT: Self = Self([0u8; 32]);
18
19 pub fn from_bytes(bytes: [u8; 32]) -> Self {
21 Self(bytes)
22 }
23
24 pub fn as_bytes(&self) -> &[u8; 32] {
26 &self.0
27 }
28
29 pub fn to_hex(&self) -> String {
31 hex::encode(self.0)
32 }
33
34 pub fn from_hex(hex_str: &str) -> Result<Self, hex::FromHexError> {
36 let mut bytes = [0u8; 32];
37 hex::decode_to_slice(hex_str, &mut bytes)?;
38 Ok(Self(bytes))
39 }
40}
41
42impl Default for BlockId {
43 fn default() -> Self {
44 Self::GENESIS_PARENT
45 }
46}
47
48impl std::fmt::Display for BlockId {
49 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50 write!(f, "{}", self.to_hex())
51 }
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
56pub struct BlockHeader {
57 pub height: u64,
59
60 pub parent: BlockId,
62
63 pub producer: SerializablePublicKey,
65
66 pub timestamp: u64,
68
69 pub tx_root: [u8; 32],
71
72 pub state_root: [u8; 32],
74
75 pub tx_count: u32,
77}
78
79impl BlockHeader {
80 pub fn id(&self) -> BlockId {
82 let bytes = serde_json::to_vec(self).expect("header serialization should not fail");
83 let mut hasher = Sha256::new();
84 hasher.update(&bytes);
85 let result = hasher.finalize();
86 let mut id = [0u8; 32];
87 id.copy_from_slice(&result);
88 BlockId(id)
89 }
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct Block {
95 pub header: BlockHeader,
97
98 pub transactions: Vec<Transaction>,
100}
101
102impl Block {
103 pub fn new(
105 height: u64,
106 parent: BlockId,
107 producer: SerializablePublicKey,
108 timestamp: u64,
109 transactions: Vec<Transaction>,
110 state_root: [u8; 32],
111 ) -> Self {
112 let tx_root = Self::compute_tx_root(&transactions);
113 let tx_count = transactions.len() as u32;
114
115 let header = BlockHeader {
116 height,
117 parent,
118 producer,
119 timestamp,
120 tx_root,
121 state_root,
122 tx_count,
123 };
124
125 Self {
126 header,
127 transactions,
128 }
129 }
130
131 pub fn genesis(producer: SerializablePublicKey) -> Self {
133 Self::new(0, BlockId::GENESIS_PARENT, producer, 0, vec![], [0u8; 32])
134 }
135
136 pub fn id(&self) -> BlockId {
138 self.header.id()
139 }
140
141 pub fn height(&self) -> u64 {
143 self.header.height
144 }
145
146 pub fn parent(&self) -> BlockId {
148 self.header.parent
149 }
150
151 pub fn timestamp(&self) -> u64 {
153 self.header.timestamp
154 }
155
156 pub fn tx_count(&self) -> usize {
158 self.transactions.len()
159 }
160
161 fn compute_tx_root(transactions: &[Transaction]) -> [u8; 32] {
163 if transactions.is_empty() {
164 return [0u8; 32];
165 }
166
167 let mut hashes: Vec<[u8; 32]> = transactions.iter().map(|tx| *tx.id().as_bytes()).collect();
169
170 while hashes.len() > 1 {
171 let mut next_level = Vec::with_capacity(hashes.len().div_ceil(2));
172
173 for chunk in hashes.chunks(2) {
174 let mut hasher = Sha256::new();
175 hasher.update(chunk[0]);
176 if chunk.len() > 1 {
177 hasher.update(chunk[1]);
178 } else {
179 hasher.update(chunk[0]); }
181 let result = hasher.finalize();
182 let mut hash = [0u8; 32];
183 hash.copy_from_slice(&result);
184 next_level.push(hash);
185 }
186
187 hashes = next_level;
188 }
189
190 hashes[0]
191 }
192
193 pub fn verify_tx_root(&self) -> bool {
195 let computed = Self::compute_tx_root(&self.transactions);
196 computed == self.header.tx_root
197 }
198
199 pub fn transaction_ids(&self) -> impl Iterator<Item = TransactionId> + '_ {
201 self.transactions.iter().map(|tx| tx.id())
202 }
203}
204
205#[derive(Debug, Clone, Serialize, Deserialize)]
207pub struct FinalizedBlock {
208 pub block: Block,
210
211 pub view: u64,
213
214 pub signatures: Vec<(SerializablePublicKey, SerializableSignature)>,
216}
217
218impl FinalizedBlock {
219 pub fn new(
221 block: Block,
222 view: u64,
223 signatures: Vec<(SerializablePublicKey, SerializableSignature)>,
224 ) -> Self {
225 Self {
226 block,
227 view,
228 signatures,
229 }
230 }
231
232 pub fn id(&self) -> BlockId {
234 self.block.id()
235 }
236
237 pub fn height(&self) -> u64 {
239 self.block.height()
240 }
241
242 pub fn signature_count(&self) -> usize {
244 self.signatures.len()
245 }
246}
247
248#[cfg(test)]
249mod tests {
250 use super::*;
251 use commonware_cryptography::{ed25519, PrivateKeyExt, Signer};
252
253 fn test_keypair() -> (SerializablePublicKey, SerializableSignature) {
254 let key = ed25519::PrivateKey::from_seed(42);
255 let sig = key.sign(Some(b"_GUTS"), b"test");
256 (
257 SerializablePublicKey::from_pubkey(&key.public_key()),
258 SerializableSignature::from_signature(&sig),
259 )
260 }
261
262 #[test]
263 fn test_block_id_roundtrip() {
264 let bytes = [0xab; 32];
265 let id = BlockId::from_bytes(bytes);
266 assert_eq!(id.as_bytes(), &bytes);
267
268 let hex = id.to_hex();
269 let parsed = BlockId::from_hex(&hex).unwrap();
270 assert_eq!(id, parsed);
271 }
272
273 #[test]
274 fn test_genesis_block() {
275 let (producer, _) = test_keypair();
276 let genesis = Block::genesis(producer);
277
278 assert_eq!(genesis.height(), 0);
279 assert_eq!(genesis.parent(), BlockId::GENESIS_PARENT);
280 assert_eq!(genesis.tx_count(), 0);
281 assert!(genesis.verify_tx_root());
282 }
283
284 #[test]
285 fn test_block_with_transactions() {
286 let (producer, signature) = test_keypair();
287
288 let tx = Transaction::CreateRepository {
289 owner: "alice".into(),
290 name: "test".into(),
291 description: "A test".into(),
292 default_branch: "main".into(),
293 visibility: "public".into(),
294 creator: producer.clone(),
295 signature: signature.clone(),
296 };
297
298 let block = Block::new(
299 1,
300 BlockId::GENESIS_PARENT,
301 producer,
302 12345,
303 vec![tx],
304 [0u8; 32],
305 );
306
307 assert_eq!(block.height(), 1);
308 assert_eq!(block.tx_count(), 1);
309 assert!(block.verify_tx_root());
310 }
311
312 #[test]
313 fn test_block_id_unique() {
314 let (producer, _) = test_keypair();
315
316 let block1 = Block::new(
317 1,
318 BlockId::GENESIS_PARENT,
319 producer.clone(),
320 12345,
321 vec![],
322 [0u8; 32],
323 );
324
325 let block2 = Block::new(
326 2, BlockId::GENESIS_PARENT,
328 producer,
329 12345,
330 vec![],
331 [0u8; 32],
332 );
333
334 assert_ne!(block1.id(), block2.id());
335 }
336
337 #[test]
338 fn test_finalized_block() {
339 let (producer, sig) = test_keypair();
340 let block = Block::genesis(producer.clone());
341 let signatures = vec![(producer, sig)];
342
343 let finalized = FinalizedBlock::new(block, 1, signatures);
344
345 assert_eq!(finalized.height(), 0);
346 assert_eq!(finalized.signature_count(), 1);
347 assert_eq!(finalized.view, 1);
348 }
349}