OpenPay (3 crates, ~13k LOC, 175 tests) op-connect sub-merchant onboarding + KYB + split-payments + payouts + 1099-K op-3ds2 3DS2.3 SCA processor (AReq/ARes/CReq/CRes/RReq/RRes + exemptions) op-tax US/EU/UK/AU/CA/IN tax with Avalara/Stripe/CCH/Vertex/TaxJar adapters Smart Byte (3 crates, ~7k LOC, 57 tests) smart-byte-libp2p libp2p transport (kad/gossipsub/mdns/autonat/relay/dcutr/identify/ping/req_resp) smart-byte-crdt LWW/GCounter/PnCounter/OrSet/LwwMap/RgaList/2P-Set + HLC + vector clock + Automerge/Yjs interop smart-byte-keri-witness KERI key-rotation cycle + witness layer + watchers + recovery + delegation EOC (3 crates, ~8k LOC, 108 tests) eoc-tools function-calling across Anthropic/OpenAI/Google/Mistral/Cohere + parallel exec + sandbox eoc-multimodal vision (CLIP/SigLIP/ColPali) + audio (Whisper/MMS) + video sampling + modality router eoc-spec-decode vanilla + SpS-with-temp + lookahead speculative decoding + EAGLE/Medusa stubs All three workspaces compile cleanly. Forbidden-unsafe, no unwrap outside tests. Co-Authored-By: Claude Opus 4.7 <[email protected]>
136 lines
3.8 KiB
Rust
136 lines
3.8 KiB
Rust
//! Vector clocks for causal-history comparisons.
|
|
//!
|
|
//! A vector clock maps each replica to the highest sequence number this
|
|
//! replica has *observed* (locally or remotely). Two clocks compare as
|
|
//! happens-before, happens-after, equal, or concurrent.
|
|
|
|
use std::collections::BTreeMap;
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::hlc::ReplicaId;
|
|
|
|
/// A vector clock keyed by replica.
|
|
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(transparent)]
|
|
pub struct VectorClock(pub BTreeMap<ReplicaId, u64>);
|
|
|
|
impl VectorClock {
|
|
/// Construct an empty vector clock.
|
|
pub fn new() -> Self {
|
|
Self(BTreeMap::new())
|
|
}
|
|
|
|
/// Read the sequence number recorded for `replica` (zero if absent).
|
|
pub fn get(&self, replica: ReplicaId) -> u64 {
|
|
self.0.get(&replica).copied().unwrap_or(0)
|
|
}
|
|
|
|
/// Record an observation: ensure the entry for `replica` is at
|
|
/// least `seq`.
|
|
pub fn observe(&mut self, replica: ReplicaId, seq: u64) {
|
|
let entry = self.0.entry(replica).or_insert(0);
|
|
if seq > *entry {
|
|
*entry = seq;
|
|
}
|
|
}
|
|
|
|
/// Bump the local replica's own counter and return the new value.
|
|
pub fn tick(&mut self, replica: ReplicaId) -> u64 {
|
|
let entry = self.0.entry(replica).or_insert(0);
|
|
*entry += 1;
|
|
*entry
|
|
}
|
|
|
|
/// True iff `self` strictly happens-before `other`: every entry in
|
|
/// `self` is `<= other`'s entry, with at least one strict `<`.
|
|
pub fn happens_before(&self, other: &Self) -> bool {
|
|
let mut at_least_one_strict = false;
|
|
// Check all entries in self are <= other.
|
|
for (k, v) in &self.0 {
|
|
let ov = other.get(*k);
|
|
if *v > ov {
|
|
return false;
|
|
}
|
|
if *v < ov {
|
|
at_least_one_strict = true;
|
|
}
|
|
}
|
|
// Any extra entries in other are strict gains.
|
|
for (k, v) in &other.0 {
|
|
if !self.0.contains_key(k) && *v > 0 {
|
|
at_least_one_strict = true;
|
|
}
|
|
}
|
|
at_least_one_strict
|
|
}
|
|
|
|
/// True iff `self` and `other` are concurrent (neither precedes the
|
|
/// other, and they are not equal).
|
|
pub fn concurrent(&self, other: &Self) -> bool {
|
|
!self.happens_before(other) && !other.happens_before(self) && self != other
|
|
}
|
|
|
|
/// Pointwise maximum of two vector clocks.
|
|
pub fn merge(&mut self, other: &Self) {
|
|
for (k, v) in &other.0 {
|
|
self.observe(*k, *v);
|
|
}
|
|
}
|
|
|
|
/// Iterate (replica, seq) entries.
|
|
pub fn iter(&self) -> impl Iterator<Item = (&ReplicaId, &u64)> {
|
|
self.0.iter()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
fn r(n: u128) -> ReplicaId {
|
|
ReplicaId::new(n)
|
|
}
|
|
|
|
#[test]
|
|
fn empty_clocks_are_equal_not_concurrent() {
|
|
let a = VectorClock::new();
|
|
let b = VectorClock::new();
|
|
assert!(!a.happens_before(&b));
|
|
assert!(!a.concurrent(&b));
|
|
}
|
|
|
|
#[test]
|
|
fn happens_before_basic() {
|
|
let mut a = VectorClock::new();
|
|
a.tick(r(1));
|
|
let mut b = a.clone();
|
|
b.tick(r(1));
|
|
assert!(a.happens_before(&b));
|
|
assert!(!b.happens_before(&a));
|
|
assert!(!a.concurrent(&b));
|
|
}
|
|
|
|
#[test]
|
|
fn concurrent_when_disjoint_ticks() {
|
|
let mut a = VectorClock::new();
|
|
a.tick(r(1));
|
|
let mut b = VectorClock::new();
|
|
b.tick(r(2));
|
|
assert!(a.concurrent(&b));
|
|
assert!(b.concurrent(&a));
|
|
}
|
|
|
|
#[test]
|
|
fn merge_is_pointwise_max() {
|
|
let mut a = VectorClock::new();
|
|
a.observe(r(1), 5);
|
|
a.observe(r(2), 1);
|
|
let mut b = VectorClock::new();
|
|
b.observe(r(1), 3);
|
|
b.observe(r(2), 7);
|
|
a.merge(&b);
|
|
assert_eq!(a.get(r(1)), 5);
|
|
assert_eq!(a.get(r(2)), 7);
|
|
}
|
|
}
|