use crate::chain::{recompute_chain, ChainAssembler};
use crate::ocel::{build_event, object_ref, SeqCounter};
use crate::types::{Blake3Hash, Receipt, Verdict};
use crate::verifier::verify;
use std::thread::sleep;
use std::time::Duration;
use rand::Rng;
pub struct ChaosVerifier {
pub latency_ms: u64,
pub corruption_probability: f64,
pub handle_drop_probability: f64,
}
impl Default for ChaosVerifier {
fn default() -> Self {
Self {
latency_ms: 500,
corruption_probability: 0.1,
handle_drop_probability: 0.1,
}
}
}
impl ChaosVerifier {
pub fn verify_with_chaos(&self, receipt: &Receipt) -> Result<Verdict, String> {
let mut rng = rand::thread_rng();
if rng.gen_bool(self.handle_drop_probability) {
return Err("ChaosError: Filesystem handle dropped mid-flight (EIO)".to_string());
}
for stage_idx in 1..=7 {
sleep(Duration::from_millis(self.latency_ms));
if stage_idx == 3 && rng.gen_bool(self.corruption_probability) {
let mut tampered = receipt.clone();
let hex = tampered.chain_hash.as_hex();
let mut chars: Vec<char> = hex.chars().collect();
chars[0] = if chars[0] == '0' { '1' } else { '0' };
tampered.chain_hash = Blake3Hash::from_hex(chars.into_iter().collect());
return Ok(verify(&tampered));
}
}
Ok(verify(receipt))
}
}
#[cfg(test)]
mod tests {
use super::*;
fn honest_receipt() -> Receipt {
let mut counter = SeqCounter::new();
let mut asm = ChainAssembler::new();
let ev = build_event("emit", vec![object_ref("o1", "artifact")], b"data", &mut counter)
.expect("build event");
asm.append(ev).expect("append event");
asm.finalize()
}
#[test]
fn prove_resilience_under_latency() {
let verifier = ChaosVerifier {
latency_ms: 100, corruption_probability: 0.0,
handle_drop_probability: 0.0,
};
let receipt = honest_receipt();
let start = std::time::Instant::now();
let verdict = verifier.verify_with_chaos(&receipt).unwrap();
let duration = start.elapsed();
assert!(verdict.accepted);
assert!(duration >= Duration::from_millis(700), "must have injected 7 stages of latency");
}
#[test]
fn prove_resilience_under_corruption() {
let verifier = ChaosVerifier {
latency_ms: 0,
corruption_probability: 1.0, handle_drop_probability: 0.0,
};
let receipt = honest_receipt();
let verdict = verifier.verify_with_chaos(&receipt).unwrap();
assert!(!verdict.accepted, "corrupted BLAKE3 must be REJECTED");
assert!(verdict.reason.contains("chain_integrity") || verdict.reason.contains("chain hash mismatch"));
}
#[test]
fn prove_resilience_under_handle_drop() {
let verifier = ChaosVerifier {
latency_ms: 0,
corruption_probability: 0.0,
handle_drop_probability: 1.0, };
let receipt = honest_receipt();
let result = verifier.verify_with_chaos(&receipt);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "ChaosError: Filesystem handle dropped mid-flight (EIO)");
}
}