Skip to main content

immutable_trace/
chain.rs

1use thiserror::Error;
2
3use crate::record::AuditRecord;
4
5#[derive(Debug, Error, PartialEq, Eq)]
6pub enum ChainError {
7    #[error("invalid previous hash at index {index}")]
8    InvalidPrevHash { index: usize },
9    #[error("invalid sequence at index {index}: expected {expected}, actual {actual}")]
10    InvalidSequence {
11        index: usize,
12        expected: u64,
13        actual: u64,
14    },
15}
16
17pub fn verify_chain(records: &[AuditRecord]) -> Result<(), ChainError> {
18    if records.is_empty() {
19        return Ok(());
20    }
21
22    for (index, record) in records.iter().enumerate() {
23        if index == 0 {
24            if record.prev_record_hash != AuditRecord::zero_hash() {
25                return Err(ChainError::InvalidPrevHash { index });
26            }
27            continue;
28        }
29
30        let previous = &records[index - 1];
31        if record.prev_record_hash != previous.hash() {
32            return Err(ChainError::InvalidPrevHash { index });
33        }
34
35        let expected_sequence = previous.sequence + 1;
36        if record.sequence != expected_sequence {
37            return Err(ChainError::InvalidSequence {
38                index,
39                expected: expected_sequence,
40                actual: record.sequence,
41            });
42        }
43    }
44
45    Ok(())
46}