clocksync
Fault-tolerant clock synchronization using Marzullo's algorithm with NULID nanosecond timestamps.
clocksync provides a decentralized clock consensus mechanism based on Marzullo's algorithm. It finds the smallest time interval consistent with the majority of time sources, producing nanosecond-precision consensus timestamps as NULID identifiers.
Features
- Marzullo's algorithm - Sweep-line interval consensus with O(n log n) complexity
- Nanosecond precision - All time values in nanoseconds via NULID timestamps
- NULID-centric - Probes exchange NULIDs, samples are built from NULID timestamps, consensus produces NULIDs
- Async
ClockSourcetrait - Implement your own probing logic for any transport (HTTP, gRPC, UDP, etc.) - WASM ready - Optional
wasmfeature for Cloudflare Workers and browser targets - Confidence tracking - Know how many sources agree on the consensus interval
- Memory safe - Zero unsafe code, panic-free production paths
- Pedantic clippy - Strict linting enforced
Installation
Add this to your Cargo.toml:
[]
= "0.2"
WASM / Cloudflare Workers
Enable the wasm feature for WASM targets:
[]
= { = "0.2", = ["wasm"] }
This activates nulid/wasm under the hood, which provides getrandom/wasm_js
and web-time for timestamp generation in browser and Workers environments.
Quick Start
Implement ClockSource
Define how your application probes remote peers. Each probe returns a ProbeResponse containing the peer's NULID and round-trip timing:
use ;
use Nulid;
use Instant;
;
Run Consensus
use consensus;
let source = MyClient;
let addrs = vec!;
let interval = consensus.await;
if let Some = interval
Use marzullo Directly
If you already have samples:
use ;
use Nulid;
let id = from_nanos;
let samples = vec!;
let interval = marzullo.expect;
assert_eq!;
assert_eq!;
How It Works
Data Flow
User implements ClockSource::probe()
→ ProbeResponse { Nulid, rtt_nanos, uncertainty_nanos }
→ Sample { lower: nanos - margin, upper: nanos + margin }
→ marzullo() sweep-line algorithm
→ Interval { lower, upper, confidence }
→ interval.nulid()
Marzullo's Algorithm
The algorithm finds the tightest interval supported by the maximum number of sources:
- Each clock sample provides an interval
[lower, upper]representing possible true time - The algorithm creates a sorted list of interval endpoints
- A sweep-line pass finds the region where the most intervals overlap
- The result is the consensus interval with a confidence ratio
Bounds Computation
When a ProbeResponse is converted to a Sample, the crate computes:
margin = rtt_nanos / 2 + uncertainty_nanos
lower = peer_nanos - margin
upper = peer_nanos + margin
Where peer_nanos is extracted from the remote peer's NULID via nulid.nanos().
API Reference
Core Types
| Type | Description |
|---|---|
ProbeResponse |
Response from probing a remote peer (NULID + RTT + uncertainty) |
Sample |
Clock sample with nanosecond interval bounds and source identifier |
Interval |
Consensus result with bounds, confidence, and NULID generation |
ClockSource |
Async trait for implementing remote clock probing |
Functions
| Function | Description |
|---|---|
marzullo(&[Sample]) |
Run Marzullo's algorithm on pre-collected samples |
consensus(&[&str], &impl ClockSource) |
Probe addresses and compute consensus |
ProbeResponse
// Create from probe results
let response = new;
response.remote_id // Nulid: the peer's NULID
response.remote_nanos // u128: peer's nanosecond timestamp
response.rtt_nanos // u128: round-trip time in nanoseconds
response.uncertainty_nanos // u128: additional uncertainty
response.margin_nanos // u128: rtt/2 + uncertainty
Sample
// From a probe response
let sample = from_response;
// Or with explicit bounds
let sample = new;
sample.lower_bound // u128: lower bound in nanoseconds
sample.upper_bound // u128: upper bound in nanoseconds
sample.remote_id // Nulid: the remote peer's NULID
sample.source // &str: source identifier
sample.width // u128: interval width
sample.midpoint // u128: interval midpoint
Interval
interval.lower // u128: consensus lower bound (nanos)
interval.upper // u128: consensus upper bound (nanos)
interval.width // u128: interval width (nanos)
interval.midpoint // u128: best estimate of true time (nanos)
interval.confidence // f64: overlapping / total sources
interval.overlapping_sources // u32: number of agreeing sources
interval.total_sources // u32: total sources sampled
interval.nulid // Nulid: NULID at consensus midpoint
Development
Building
Testing
Linting
All CI Checks
License
Licensed under the MIT License. See LICENSE for details.