Skip to main content

moloch_core/
block.rs

1//! Block types for Moloch.
2//!
3//! Blocks batch audit events together and link to form the chain.
4
5use 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/// Unique identifier for a block (hash of header).
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
14pub struct BlockHash(pub Hash);
15
16impl BlockHash {
17    /// The zero block hash (used for genesis parent).
18    pub const ZERO: Self = Self(Hash::ZERO);
19
20    /// Get the underlying hash.
21    pub fn as_hash(&self) -> &Hash {
22        &self.0
23    }
24
25    /// Create a block hash from a header.
26    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/// Identifies a sealer (block producer).
38#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
39pub struct SealerId {
40    /// Sealer's public key.
41    pub key: PublicKey,
42    /// Human-readable name.
43    pub name: Option<String>,
44}
45
46impl SealerId {
47    /// Create a new sealer ID.
48    pub fn new(key: PublicKey) -> Self {
49        Self { key, name: None }
50    }
51
52    /// Add a display name.
53    pub fn with_name(mut self, name: impl Into<String>) -> Self {
54        self.name = Some(name.into());
55        self
56    }
57
58    /// Get the unique hash ID for this sealer.
59    pub fn id(&self) -> Hash {
60        self.key.id()
61    }
62
63    /// Get the public key.
64    pub fn as_pubkey(&self) -> &PublicKey {
65        &self.key
66    }
67}
68
69/// Block header containing metadata and proofs.
70#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
71pub struct BlockHeader {
72    /// Block height (monotonically increasing).
73    pub height: u64,
74
75    /// Hash of parent block header.
76    pub parent: BlockHash,
77
78    /// Merkle root of events in this block.
79    pub events_root: Hash,
80
81    /// Number of events in this block.
82    pub events_count: u32,
83
84    /// MMR root after this block (cumulative chain state).
85    pub mmr_root: Hash,
86
87    /// Sealer's timestamp (must be >= parent timestamp), as Unix millis.
88    #[serde(with = "chrono::serde::ts_milliseconds")]
89    pub timestamp: DateTime<Utc>,
90
91    /// Identity of the sealer who produced this block.
92    pub sealer: SealerId,
93
94    /// Sealer's signature over the header (excluding this field).
95    pub seal: Sig,
96}
97
98impl BlockHeader {
99    /// Get the bytes to be signed (everything except the seal).
100    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    /// Compute the hash of this header.
114    pub fn hash(&self) -> BlockHash {
115        BlockHash(hash(&self.signing_bytes()))
116    }
117
118    /// Create a new header with the given seal.
119    pub fn with_seal(mut self, seal: Sig) -> Self {
120        self.seal = seal;
121        self
122    }
123
124    /// Verify the seal signature.
125    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    /// Validate this header against its parent.
133    pub fn validate(&self, parent: Option<&BlockHeader>) -> Result<()> {
134        // Verify seal
135        self.verify_seal()?;
136
137        match parent {
138            Some(p) => {
139                // Height must be parent + 1
140                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                // Parent hash must match
149                if self.parent != p.hash() {
150                    return Err(Error::invalid_block("parent hash mismatch"));
151                }
152
153                // Timestamp must be >= parent
154                if self.timestamp < p.timestamp {
155                    return Err(Error::invalid_block("timestamp before parent"));
156                }
157            }
158            None => {
159                // Genesis block
160                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/// Helper for signing (excludes seal field).
174#[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/// A complete block with header and events.
187#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
188pub struct Block {
189    pub header: BlockHeader,
190    pub events: Vec<AuditEvent>,
191}
192
193impl Block {
194    /// Get the block hash.
195    pub fn hash(&self) -> BlockHash {
196        self.header.hash()
197    }
198
199    /// Validate the block (sequential event verification).
200    ///
201    /// For better performance with many events, use `validate_batch()` instead.
202    pub fn validate(&self, parent: Option<&BlockHeader>) -> Result<()> {
203        // Validate header
204        self.header.validate(parent)?;
205
206        // Validate events count matches
207        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        // Validate events merkle root
216        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        // Validate each event
222        for event in &self.events {
223            event.validate()?;
224        }
225
226        Ok(())
227    }
228
229    /// Validate the block using batch signature verification.
230    ///
231    /// This is 3-8x faster than `validate()` for blocks with many events,
232    /// using Arcanum's optimized Ed25519 batch verifier.
233    ///
234    /// # Performance
235    /// - 10 events: ~2x faster
236    /// - 100 events: ~4x faster
237    /// - 1000 events: ~6-8x faster
238    pub fn validate_batch(&self, parent: Option<&BlockHeader>) -> Result<()> {
239        // Validate header
240        self.header.validate(parent)?;
241
242        // Validate events count matches
243        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        // Validate events merkle root
252        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        // Batch verify all event signatures at once
258        crate::batch_verify_events(&self.events)?;
259
260        // Check event timestamps (can't be batched)
261        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    /// Validate the block using fully parallel processing.
272    ///
273    /// Uses batch signature verification (the main speedup) combined with
274    /// parallel canonical bytes computation for large blocks (1000+ events).
275    ///
276    /// Note: Parallel merkle tree is not used because BLAKE3 is already
277    /// SIMD-accelerated, making parallelization overhead counterproductive.
278    ///
279    /// # Performance
280    /// - Uses all available CPU cores for signature verification
281    /// - 100 events: ~2.5x faster than sequential
282    /// - 500 events: ~2.5x faster than sequential
283    /// - 1000+ events: ~2.7x faster than sequential (parallel canonical bytes kicks in)
284    ///
285    /// # When to Use
286    /// - Blocks with many events where signature verification dominates
287    /// - For bulk validation of historical blocks
288    pub fn validate_parallel(&self, parent: Option<&BlockHeader>) -> Result<()> {
289        // Validate header (single signature, not worth parallelizing)
290        self.header.validate(parent)?;
291
292        // Validate events count matches
293        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        // Sequential merkle root (faster than parallel due to BLAKE3 SIMD)
302        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        // Use parallel canonical bytes for large batches, otherwise batch only
308        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        // Check event timestamps (fast, not worth parallelizing)
315        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    /// Get event IDs in this block.
326    pub fn event_ids(&self) -> Vec<EventId> {
327        self.events.iter().map(|e| e.id()).collect()
328    }
329}
330
331/// Compute the merkle root of a list of events.
332pub fn compute_events_root(events: &[AuditEvent]) -> Hash {
333    if events.is_empty() {
334        return Hash::ZERO;
335    }
336
337    // Get leaf hashes
338    let mut hashes: Vec<Hash> = events.iter().map(|e| e.id().0).collect();
339
340    // Pad to power of 2
341    while hashes.len() & (hashes.len() - 1) != 0 {
342        hashes.push(*hashes.last().unwrap());
343    }
344
345    // Build tree bottom-up
346    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
357/// Compute the merkle root using parallel hashing.
358///
359/// Uses Rayon to parallelize:
360/// 1. Leaf hash computation (event ID extraction)
361/// 2. Each level of the merkle tree (when level is large enough)
362///
363/// # Performance
364/// - 100 events: ~1.2x faster than sequential
365/// - 1000 events: ~2-3x faster than sequential
366/// - Automatically falls back to sequential for small inputs
367pub 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    // Parallel leaf hash extraction
375    let mut hashes: Vec<Hash> = events.par_iter().map(|e| e.id().0).collect();
376
377    // Pad to power of 2
378    while hashes.len() & (hashes.len() - 1) != 0 {
379        hashes.push(*hashes.last().unwrap());
380    }
381
382    // Build tree bottom-up with parallel levels for large trees
383    while hashes.len() > 1 {
384        if hashes.len() >= 64 {
385            // Parallel hash pairing for large levels
386            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            // Sequential for small levels (parallelization overhead not worth it)
393            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
404/// Builder for creating blocks.
405pub struct BlockBuilder {
406    parent: Option<BlockHeader>,
407    events: Vec<AuditEvent>,
408    sealer: SealerId,
409    mmr_root: Hash,
410}
411
412impl BlockBuilder {
413    /// Create a new block builder.
414    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    /// Set the parent block.
424    pub fn parent(mut self, parent: BlockHeader) -> Self {
425        self.parent = Some(parent);
426        self
427    }
428
429    /// Add events.
430    pub fn events(mut self, events: Vec<AuditEvent>) -> Self {
431        self.events = events;
432        self
433    }
434
435    /// Set the MMR root (computed externally).
436    pub fn mmr_root(mut self, root: Hash) -> Self {
437        self.mmr_root = root;
438        self
439    }
440
441    /// Build and seal the block.
442    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        // Genesis
517        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        // Block 1
524        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        // Block 2
534        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        // Tamper with height
574        block.header.height = 999;
575
576        // Validation should fail (signature doesn't match)
577        assert!(block.validate(None).is_err());
578    }
579}