extern crate alloc;
use core::sync::atomic::Ordering;
use super::super::stamp::Kairos;
use super::super::time::VirtualTimeSource;
use super::state::ClockState;
use super::{Clock, ClockConfig};
fn any_sub_ceiling_stamp() -> Kairos {
let stamp = Kairos::new(kani::any(), kani::any(), kani::any(), kani::any::<u16>());
kani::assume(stamp.physical() < u64::MAX);
stamp
}
#[kani::proof]
fn clock_state_roundtrips_and_init_tag_is_unforgeable() {
let physical: u64 = kani::any();
let logical: u16 = kani::any();
let minted = ClockState::minted(physical, logical);
assert_eq!(minted.last(), Some((physical, logical)));
assert!(ClockState::UNINIT.last().is_none());
assert_ne!(minted.0, ClockState::UNINIT.0);
}
#[kani::proof]
#[kani::unwind(3)]
fn now_strictly_increases_under_any_skew() {
let source = VirtualTimeSource::new(kani::any());
let driver = source.clone();
let clock = Clock::new(source, 1, ClockConfig::default()).unwrap();
let first = clock.now(0u16);
driver.set(kani::any());
let second = clock.now(0u16);
assert!(second > first, "per-clock monotonicity must hold");
}
#[kani::proof]
#[kani::unwind(3)]
fn now_strictly_increases_after_arbitrary_observe() {
let remote = any_sub_ceiling_stamp();
let source = VirtualTimeSource::new(kani::any());
let driver = source.clone();
let clock = Clock::new(source, 1, ClockConfig::default()).unwrap();
clock.observe(remote);
driver.set(kani::any());
let first = clock.now(0u16);
driver.set(kani::any());
let second = clock.now(0u16);
assert!(
second > first,
"monotonicity must survive any received stamp"
);
}
#[kani::proof]
#[kani::unwind(3)]
fn after_dominates_previous_on_fresh_clock() {
let previous = any_sub_ceiling_stamp();
let source = VirtualTimeSource::new(kani::any());
let clock = Clock::new(source, 1, ClockConfig::default()).unwrap();
let minted = clock.after(previous, kani::any::<u16>());
assert!(minted > previous, "after must strictly dominate its input");
}
#[kani::proof]
#[kani::unwind(3)]
fn after_dominates_previous_on_warm_clock() {
let previous = any_sub_ceiling_stamp();
let source = VirtualTimeSource::new(kani::any());
let driver = source.clone();
let clock = Clock::new(source, 1, ClockConfig::default()).unwrap();
let _ = clock.now(0u16);
driver.set(kani::any());
let minted = clock.after(previous, kani::any::<u16>());
assert!(minted > previous, "after must strictly dominate its input");
}
#[kani::proof]
#[kani::unwind(3)]
fn observe_then_now_dominates_remote() {
let remote = any_sub_ceiling_stamp();
let source = VirtualTimeSource::new(kani::any());
let driver = source.clone();
let clock = Clock::new(source, 1, ClockConfig::default()).unwrap();
clock.observe(remote);
driver.set(kani::any());
let minted = clock.now(0u16);
assert!(
minted > remote,
"every stamp after a receive must exceed it"
);
}
#[kani::proof]
#[kani::unwind(3)]
fn try_observe_rejection_leaves_clock_unchanged() {
let source = VirtualTimeSource::new(kani::any());
let clock = Clock::new(source, 1, ClockConfig::default()).unwrap();
if kani::any() {
let _ = clock.now(0u16);
}
let before = clock.state.load(Ordering::SeqCst);
let remote = Kairos::new(kani::any(), kani::any(), kani::any(), kani::any::<u16>());
let bound: u64 = kani::any();
if clock.try_observe(remote, bound).is_err() {
let after = clock.state.load(Ordering::SeqCst);
assert_eq!(before, after, "a rejected receive must not move the clock");
}
}
#[kani::proof]
#[kani::unwind(3)]
fn try_observe_admission_dominates_remote() {
let remote = any_sub_ceiling_stamp();
let source = VirtualTimeSource::new(kani::any());
let driver = source.clone();
let clock = Clock::new(source, 1, ClockConfig::default()).unwrap();
let bound: u64 = kani::any();
if clock.try_observe(remote, bound).is_ok() {
driver.set(kani::any());
let minted = clock.now(0u16);
assert!(
minted > remote,
"an admitted receive must behave as observe"
);
}
}
#[kani::proof]
#[kani::unwind(6)]
fn run_mint_equals_iterated_sends_over_a_frozen_reading() {
let last: Option<(u64, u16)> = if kani::any() {
Some((kani::any(), kani::any()))
} else {
None
};
let reading: u64 = kani::any();
let len: u32 = kani::any();
kani::assume(len >= 1 && len <= 4);
let run = super::fold::advance_run(last, reading, len);
let mut state = last;
let mut first = (0u64, 0u16);
let mut max_forward: u64 = 0;
let mut max_backward: u64 = 0;
let mut i: u32 = 0;
while i < len {
let step = super::fold::advance(state, reading, None);
if i == 0 {
first = (step.physical, step.logical);
}
if step.forward_skew > max_forward {
max_forward = step.forward_skew;
}
if step.backward_skew > max_backward {
max_backward = step.backward_skew;
}
assert_eq!(
super::fold::rank_offset(first.0, first.1, u64::from(i)),
(step.physical, step.logical),
"member i must be the closed-form offset of the first"
);
state = Some((step.physical, step.logical));
i += 1;
}
assert_eq!(
(run.first_physical, run.first_logical),
first,
"the run's first stamp must be the single mint's"
);
assert_eq!(
Some((run.physical, run.logical)),
state,
"the run must commit exactly the last iterated send"
);
assert_eq!(
run.forward_skew, max_forward,
"the run reports the iterated forward-skew maximum"
);
assert_eq!(
run.backward_skew, max_backward,
"the run reports the iterated backward-skew maximum"
);
}
#[kani::proof]
fn run_members_strictly_ascend_below_the_ceiling() {
let physical: u64 = kani::any();
let logical: u16 = kani::any();
kani::assume(logical < u16::MAX);
let len: u32 = kani::any();
kani::assume(len >= 2);
let index: u32 = kani::any();
kani::assume(index < len - 1);
let total = u64::from(logical) + u64::from(index) + 1;
kani::assume(physical.checked_add(total / u64::from(u16::MAX)).is_some());
let first = Kairos::new(physical, logical, kani::any(), kani::any::<u16>());
let run = super::run::KairosRun::new(first, len);
let member = run.get(index).unwrap();
let successor = run.get(index + 1).unwrap();
assert!(
successor > member,
"run members must strictly ascend below the ceiling"
);
}
#[kani::proof]
#[kani::unwind(5)]
fn now_after_a_run_dominates_every_member() {
let source = VirtualTimeSource::new(kani::any());
let driver = source.clone();
let clock = Clock::new(source, 1, ClockConfig::default()).unwrap();
let len: u32 = kani::any();
kani::assume(len >= 1 && len <= 3);
let run = clock.now_run(core::num::NonZeroU32::new(len).unwrap(), 0u16);
kani::assume(run.last().physical() < u64::MAX);
driver.set(kani::any());
let next = clock.now(0u16);
let mut i: u32 = 0;
while i < len {
assert!(
next > run.get(i).unwrap(),
"a mint after a run must dominate every reserved member"
);
i += 1;
}
}
#[kani::proof]
fn snapshot_rank_step_matches_the_clock_fold() {
let physical: u64 = kani::any();
let logical: u16 = kani::any();
let advance = super::fold::advance(Some((physical, logical)), physical, None);
assert_eq!(
crate::metis::rank_successor(physical, logical),
(advance.physical, advance.logical),
"the codec successor must be the fold's frozen-reading commit"
);
}