2 releases (1 stable)

2.0.0 Feb 25, 2021

#6 in #byzantine


Used in byztimed

Apache-2.0

85KB
1.5K SLoC

Rust 819 SLoC // 0.1% comments C 740 SLoC // 0.1% comments

Byztime is a Byzantine-fault-tolerant protocol for synchronizing time among a group of peers, without reliance on any external authority. This crate wraps byztime_sys (which in turn wraps the C library libbyztime) to provide an idiomatic Rust API for communication from byztimed to applications which consume time from it.


lib.rs:

Byztime is a Byzantine-fault-tolerant protocol for synchronizing time among a group of peers, without reliance on any external authority. This crate wraps [byztime_sys] (which in turn wraps the C library libbyztime) to provide an idiomatic Rust API for communication from byztimed to applications which consume time from it.

libbyztime employs a "blackboard" pattern of one-way communication. The daemon writes time offsets and error bounds to a timedata file, which is a regular file containing a lock-free data structure. Consumers simply read from the file without altering it or sending any sort of query to the daemon.

Byztime recognizes three kinds of clocks:

  • The local clock is a hardware clock that represents the time elapsed since some arbitrary epoch, such as the last reboot. On Linux this is realized by CLOCK_MONOTONIC_RAW.

  • The real clock tracks wall time (CLOCK_REALTIME). Byztime mostly avoids relying on it but does use it for recovery if the network loses quorum in a mass reboot.

  • The global clock is the one that Byztime synchronizes. At first initialization it is set to the real clock. Eventually it should be expected to drift, though, because Byztime is designed to keep nodes synchronized only with each other and not with anything else.

The Byztime daemon determines the offset between the global and local clocks, a maximum error bound on that offset, and the local time as of which that error bound is valid. It records these values in the timedata file. Consumers read them and then obtain the local time from the operating system. From these inputs they can compute the global time, as well as recomputing error bounds to account for any drift that may have occurred since the last timedata update.

Simple consumers will want to use this crate as follows:

  1. Optionally, call [install_sigbus_handler].

  2. Call ConsumerContext::open with the path to timedata file to obtain a Context object.

  3. Optionally, call Context::slew. Sleep and retry in a loop until it succeeds.

  4. Call Context::global_time to get a timestamp with error bounds.

Dependencies

~0–0.9MB
~15K SLoC