1use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7
8use crate::crypto::{hash, hash_pair, Hash, PublicKey, SecretKey, Sig};
9use crate::error::{Error, Result};
10use crate::event::{AuditEvent, EventId};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
14pub struct BlockHash(pub Hash);
15
16impl BlockHash {
17 pub const ZERO: Self = Self(Hash::ZERO);
19
20 pub fn as_hash(&self) -> &Hash {
22 &self.0
23 }
24
25 pub fn from_header(header: &BlockHeader) -> Self {
27 header.hash()
28 }
29}
30
31impl std::fmt::Display for BlockHash {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 write!(f, "{}", self.0)
34 }
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
39pub struct SealerId {
40 pub key: PublicKey,
42 pub name: Option<String>,
44}
45
46impl SealerId {
47 pub fn new(key: PublicKey) -> Self {
49 Self { key, name: None }
50 }
51
52 pub fn with_name(mut self, name: impl Into<String>) -> Self {
54 self.name = Some(name.into());
55 self
56 }
57
58 pub fn id(&self) -> Hash {
60 self.key.id()
61 }
62
63 pub fn as_pubkey(&self) -> &PublicKey {
65 &self.key
66 }
67}
68
69#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
71pub struct BlockHeader {
72 pub height: u64,
74
75 pub parent: BlockHash,
77
78 pub events_root: Hash,
80
81 pub events_count: u32,
83
84 pub mmr_root: Hash,
86
87 #[serde(with = "chrono::serde::ts_milliseconds")]
89 pub timestamp: DateTime<Utc>,
90
91 pub sealer: SealerId,
93
94 pub seal: Sig,
96}
97
98impl BlockHeader {
99 pub fn signing_bytes(&self) -> Vec<u8> {
101 let signable = SignableHeader {
102 height: self.height,
103 parent: &self.parent,
104 events_root: &self.events_root,
105 events_count: self.events_count,
106 mmr_root: &self.mmr_root,
107 timestamp: self.timestamp,
108 sealer: &self.sealer,
109 };
110 bincode::serialize(&signable).expect("serialization should not fail")
111 }
112
113 pub fn hash(&self) -> BlockHash {
115 BlockHash(hash(&self.signing_bytes()))
116 }
117
118 pub fn with_seal(mut self, seal: Sig) -> Self {
120 self.seal = seal;
121 self
122 }
123
124 pub fn verify_seal(&self) -> Result<()> {
126 self.sealer
127 .key
128 .verify(&self.signing_bytes(), &self.seal)
129 .map_err(|_| Error::invalid_block("invalid seal signature"))
130 }
131
132 pub fn validate(&self, parent: Option<&BlockHeader>) -> Result<()> {
134 self.verify_seal()?;
136
137 match parent {
138 Some(p) => {
139 if self.height != p.height + 1 {
141 return Err(Error::invalid_block(format!(
142 "height {} should be {}",
143 self.height,
144 p.height + 1
145 )));
146 }
147
148 if self.parent != p.hash() {
150 return Err(Error::invalid_block("parent hash mismatch"));
151 }
152
153 if self.timestamp < p.timestamp {
155 return Err(Error::invalid_block("timestamp before parent"));
156 }
157 }
158 None => {
159 if self.height != 0 {
161 return Err(Error::invalid_block("genesis must have height 0"));
162 }
163 if self.parent != BlockHash::ZERO {
164 return Err(Error::invalid_block("genesis must have zero parent"));
165 }
166 }
167 }
168
169 Ok(())
170 }
171}
172
173#[derive(Serialize)]
175struct SignableHeader<'a> {
176 height: u64,
177 parent: &'a BlockHash,
178 events_root: &'a Hash,
179 events_count: u32,
180 mmr_root: &'a Hash,
181 #[serde(with = "chrono::serde::ts_milliseconds")]
182 timestamp: DateTime<Utc>,
183 sealer: &'a SealerId,
184}
185
186#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
188pub struct Block {
189 pub header: BlockHeader,
190 pub events: Vec<AuditEvent>,
191}
192
193impl Block {
194 pub fn hash(&self) -> BlockHash {
196 self.header.hash()
197 }
198
199 pub fn validate(&self, parent: Option<&BlockHeader>) -> Result<()> {
203 self.header.validate(parent)?;
205
206 if self.events.len() as u32 != self.header.events_count {
208 return Err(Error::invalid_block(format!(
209 "events count mismatch: {} vs {}",
210 self.events.len(),
211 self.header.events_count
212 )));
213 }
214
215 let computed_root = compute_events_root(&self.events);
217 if computed_root != self.header.events_root {
218 return Err(Error::invalid_block("events root mismatch"));
219 }
220
221 for event in &self.events {
223 event.validate()?;
224 }
225
226 Ok(())
227 }
228
229 pub fn validate_batch(&self, parent: Option<&BlockHeader>) -> Result<()> {
239 self.header.validate(parent)?;
241
242 if self.events.len() as u32 != self.header.events_count {
244 return Err(Error::invalid_block(format!(
245 "events count mismatch: {} vs {}",
246 self.events.len(),
247 self.header.events_count
248 )));
249 }
250
251 let computed_root = compute_events_root(&self.events);
253 if computed_root != self.header.events_root {
254 return Err(Error::invalid_block("events root mismatch"));
255 }
256
257 crate::batch_verify_events(&self.events)?;
259
260 let now = chrono::Utc::now();
262 for event in &self.events {
263 if event.event_time > now + chrono::Duration::minutes(5) {
264 return Err(Error::invalid_event("event_time is in the future"));
265 }
266 }
267
268 Ok(())
269 }
270
271 pub fn validate_parallel(&self, parent: Option<&BlockHeader>) -> Result<()> {
289 self.header.validate(parent)?;
291
292 if self.events.len() as u32 != self.header.events_count {
294 return Err(Error::invalid_block(format!(
295 "events count mismatch: {} vs {}",
296 self.events.len(),
297 self.header.events_count
298 )));
299 }
300
301 let computed_root = compute_events_root(&self.events);
303 if computed_root != self.header.events_root {
304 return Err(Error::invalid_block("events root mismatch"));
305 }
306
307 if self.events.len() >= 1000 {
309 crate::batch_verify_events_parallel(&self.events)?;
310 } else {
311 crate::batch_verify_events(&self.events)?;
312 }
313
314 let now = chrono::Utc::now();
316 for event in &self.events {
317 if event.event_time > now + chrono::Duration::minutes(5) {
318 return Err(Error::invalid_event("event_time is in the future"));
319 }
320 }
321
322 Ok(())
323 }
324
325 pub fn event_ids(&self) -> Vec<EventId> {
327 self.events.iter().map(|e| e.id()).collect()
328 }
329}
330
331pub fn compute_events_root(events: &[AuditEvent]) -> Hash {
333 if events.is_empty() {
334 return Hash::ZERO;
335 }
336
337 let mut hashes: Vec<Hash> = events.iter().map(|e| e.id().0).collect();
339
340 while hashes.len() & (hashes.len() - 1) != 0 {
342 hashes.push(*hashes.last().unwrap());
343 }
344
345 while hashes.len() > 1 {
347 let mut next_level = Vec::with_capacity(hashes.len() / 2);
348 for pair in hashes.chunks(2) {
349 next_level.push(hash_pair(pair[0], pair[1]));
350 }
351 hashes = next_level;
352 }
353
354 hashes[0]
355}
356
357pub fn compute_events_root_parallel(events: &[AuditEvent]) -> Hash {
368 use rayon::prelude::*;
369
370 if events.is_empty() {
371 return Hash::ZERO;
372 }
373
374 let mut hashes: Vec<Hash> = events.par_iter().map(|e| e.id().0).collect();
376
377 while hashes.len() & (hashes.len() - 1) != 0 {
379 hashes.push(*hashes.last().unwrap());
380 }
381
382 while hashes.len() > 1 {
384 if hashes.len() >= 64 {
385 let pairs: Vec<_> = hashes.chunks(2).collect();
387 hashes = pairs
388 .par_iter()
389 .map(|pair| hash_pair(pair[0], pair[1]))
390 .collect();
391 } else {
392 let mut next_level = Vec::with_capacity(hashes.len() / 2);
394 for pair in hashes.chunks(2) {
395 next_level.push(hash_pair(pair[0], pair[1]));
396 }
397 hashes = next_level;
398 }
399 }
400
401 hashes[0]
402}
403
404pub struct BlockBuilder {
406 parent: Option<BlockHeader>,
407 events: Vec<AuditEvent>,
408 sealer: SealerId,
409 mmr_root: Hash,
410}
411
412impl BlockBuilder {
413 pub fn new(sealer: SealerId) -> Self {
415 Self {
416 parent: None,
417 events: Vec::new(),
418 sealer,
419 mmr_root: Hash::ZERO,
420 }
421 }
422
423 pub fn parent(mut self, parent: BlockHeader) -> Self {
425 self.parent = Some(parent);
426 self
427 }
428
429 pub fn events(mut self, events: Vec<AuditEvent>) -> Self {
431 self.events = events;
432 self
433 }
434
435 pub fn mmr_root(mut self, root: Hash) -> Self {
437 self.mmr_root = root;
438 self
439 }
440
441 pub fn seal(self, key: &SecretKey) -> Block {
443 let (height, parent_hash) = match &self.parent {
444 Some(p) => (p.height + 1, p.hash()),
445 None => (0, BlockHash::ZERO),
446 };
447
448 let events_root = compute_events_root(&self.events);
449 let events_count = self.events.len() as u32;
450
451 let header = BlockHeader {
452 height,
453 parent: parent_hash,
454 events_root,
455 events_count,
456 mmr_root: self.mmr_root,
457 timestamp: Utc::now(),
458 sealer: self.sealer,
459 seal: Sig::empty(),
460 };
461
462 let seal = key.sign(&header.signing_bytes());
463 let header = header.with_seal(seal);
464
465 Block {
466 header,
467 events: self.events,
468 }
469 }
470}
471
472#[cfg(test)]
473mod tests {
474 use super::*;
475 use crate::crypto::SecretKey;
476 use crate::event::{ActorId, ActorKind, EventType, ResourceId, ResourceKind};
477
478 fn test_sealer() -> (SecretKey, SealerId) {
479 let key = SecretKey::generate();
480 let sealer = SealerId::new(key.public_key()).with_name("test-sealer");
481 (key, sealer)
482 }
483
484 fn test_event(key: &SecretKey) -> AuditEvent {
485 let actor = ActorId::new(key.public_key(), ActorKind::User);
486 let resource = ResourceId::new(ResourceKind::Repository, "test");
487
488 AuditEvent::builder()
489 .now()
490 .event_type(EventType::Push {
491 force: false,
492 commits: 1,
493 })
494 .actor(actor)
495 .resource(resource)
496 .sign(key)
497 .unwrap()
498 }
499
500 #[test]
501 fn test_genesis_block() {
502 let (key, sealer) = test_sealer();
503 let event = test_event(&key);
504
505 let block = BlockBuilder::new(sealer).events(vec![event]).seal(&key);
506
507 assert_eq!(block.header.height, 0);
508 assert_eq!(block.header.parent, BlockHash::ZERO);
509 assert!(block.validate(None).is_ok());
510 }
511
512 #[test]
513 fn test_block_chain() {
514 let (key, sealer) = test_sealer();
515
516 let genesis = BlockBuilder::new(sealer.clone())
518 .events(vec![test_event(&key)])
519 .seal(&key);
520
521 assert!(genesis.validate(None).is_ok());
522
523 let block1 = BlockBuilder::new(sealer.clone())
525 .parent(genesis.header.clone())
526 .events(vec![test_event(&key)])
527 .seal(&key);
528
529 assert!(block1.validate(Some(&genesis.header)).is_ok());
530 assert_eq!(block1.header.height, 1);
531 assert_eq!(block1.header.parent, genesis.hash());
532
533 let block2 = BlockBuilder::new(sealer)
535 .parent(block1.header.clone())
536 .events(vec![test_event(&key), test_event(&key)])
537 .seal(&key);
538
539 assert!(block2.validate(Some(&block1.header)).is_ok());
540 assert_eq!(block2.header.height, 2);
541 }
542
543 #[test]
544 fn test_empty_block() {
545 let (key, sealer) = test_sealer();
546
547 let block = BlockBuilder::new(sealer).events(vec![]).seal(&key);
548
549 assert!(block.validate(None).is_ok());
550 assert_eq!(block.header.events_count, 0);
551 assert_eq!(block.header.events_root, Hash::ZERO);
552 }
553
554 #[test]
555 fn test_events_root_deterministic() {
556 let key = SecretKey::generate();
557 let events = vec![test_event(&key), test_event(&key)];
558
559 let root1 = compute_events_root(&events);
560 let root2 = compute_events_root(&events);
561
562 assert_eq!(root1, root2);
563 }
564
565 #[test]
566 fn test_tampered_block_fails() {
567 let (key, sealer) = test_sealer();
568
569 let mut block = BlockBuilder::new(sealer)
570 .events(vec![test_event(&key)])
571 .seal(&key);
572
573 block.header.height = 999;
575
576 assert!(block.validate(None).is_err());
578 }
579}