Used to generate and compare bounded timestamps.

Overview

ClockBound

Summary:

ClockBound allows you to generate and compare bounded timestamps that include accumulated error as reported from the local chronyd process. On every request, ClockBound uses two pieces of information: the current time and the associated absolute error range, which is also known as the clock error bound. This means that the “true” time of a ClockBound timestamp is within a set range.

Using ClockBound with a consistent, trusted time service will allow you to compare timestamps to determine order and consistency for events and transactions, independent from the instances’ respective geographic locations. We recommend you use the Amazon Time Sync Service, a highly accurate and reliable time reference that is natively accessible from Amazon EC2 instances, to get the most out of ClockBound on your AWS infrastructure. For more information on the Amazon Time Sync Service, see the EC2 User Guide.

Calculations:

Clock accuracy is a measure of clock error, typically defined as the offset to UTC. This clock error is the difference between the observed time on the computer and reference time (also known as true time). In an NTP architecture, this error can be bounded using three measurements that are defined by the protocol:

  • Local offset (the system time): The residual adjustment to be applied to the operating system clock.
  • Root dispersion: The accumulation of clock drift at each NTP server on the path to the reference clock.
  • Root delay: The accumulation of network delays on the path to the reference clock.

The clock error bound is calculated using the formula below:

Clock Error Bound = |Local Offset| + Root Dispersion + (Root Delay / 2)

Clock Error Bound Image
Figure 1: The clock error bound provides a bound on the worst case offset of a clock with regard to “true time”.

The combination of local offset, root dispersion, and root delay provides us with a clock error bound. For a given reading of the clock C(t) at true time t, this bound makes sure that true time exists within the clock error bound. The clock error bound is used as a proxy for clock accuracy and measures the worst case scenario (see Figure 1). Therefore, clock error bound is the main metric used to determine the accuracy of an NTP service.

ClockBound uses this clock error bound to return a bounded range of timestamps. This is calculated by adding and subtracting the clock error bound from the timestamp provided by a system's clock. It also contains functionality to check if a given timestamp is in the past or future. This allows users to have consistency when dealing with time sensitive transactions.

Usage

ClockBound is composed of two parts:
ClockBoundD - A daemon to provide clients with an error bounded timestamp interval.
ClockBoundC - A client library to communicate with ClockBoundD.

To use ClockBound you first need to install and set up ClockBoundD. See the ClockBoundD README for more info.

Once ClockBoundD is set up you will need a client to communicate with it. The ClockBoundC client library is the recommended method of usage from a rust codebase.

Custom Client

The ClockBound Protocol is provided if there is interest in creating a custom client.

Clients can be created in any programming language that can communicate with Unix Datagram Sockets:

  1. Bind the client to its own Unix Datagram Socket.
  2. Connect the client's Unix Datagram Socket to ClockBoundD's own socket.
  3. Send and receive messages as defined in the ClockBound Protocol.

See the implementation in ClockBoundC as an example.

Security

See CONTRIBUTING for more information.

License

ClockBoundC is licensed under the Apache 2.0 LICENSE.

ClockBoundD is licensed under the GPL v2 LICENSE

Comments
  • clock-bound-c: use array instead of vec for performance

    clock-bound-c: use array instead of vec for performance

    Issue #, if available:

    None

    Description of changes:

    I found that you here use vector to get timestamps, IMO, these functions are highly frequently called, so it is better to use array instead of vector.

    I wrote a simple benchmark below:

    #![feature(test)]
    extern crate test;
    use test::{black_box, Bencher};
    #[bench]
    fn bench_vec(b: &mut Bencher) {
        b.iter(|| {
            for _ in 0..16 {
                let mut request: Vec<u8> = Vec::new();
                // Inner closure, the actual test
                for i in 0..4 {
                    request.push(i);
                }
                black_box(request);
            }
        });
    }
    #[bench]
    fn bench_vec_with_capacity(b: &mut Bencher) {
        b.iter(|| {
            for _ in 0..16 {
                let mut request: Vec<u8> = Vec::with_capacity(4);
                // Inner closure, the actual test
                for i in 0..4 {
                    request.push(i);
                }
                black_box(request);
            }
        });
    }
    #[bench]
    fn bench_array(b: &mut Bencher) {
        b.iter(|| {
            for _ in 0..16 {
                let mut request: [u8; 4] = [0; 4];
                // Inner closure, the actual test
                for i in 0..4 {
                    request[i] = i as u8;
                }
                black_box(request);
            }
        });
    }
    

    The benchmark result is:

    test bench_array            ... bench:           4 ns/iter (+/- 0)
    test bench_vec               ... bench:       1,014 ns/iter (+/- 143)
    test bench_vec_with_capacity ... bench:         977 ns/iter (+/- 70)
    

    As you can see, using array gains a better performance.

    Because this repo doesn't have any unit tests, I have to test it by myself, seem it can work well, like:

    cargo run --example now /run/clockboundd/clockboundd.sock
    The UTC timestamp 2021-12-14 14:24:20.048961000 has the following error bounds.
    In nanoseconds since the Unix epoch: (1639491860040783810,1639491860057138190)
    In UTC in date/time format: (2021-12-14 14:24:20.040783810, 2021-12-14 14:24:20.057138190)
    
    cargo run --example before /run/clockboundd/clockboundd.sock
    1639491872937419000 nanoseconds since the Unix Epoch is not before the current time's error bounds.
    Waiting 1 second...
    1639491872937419000 nanoseconds since the Unix Epoch is before the current time's error bounds.
    
    cargo run --example after /run/clockboundd/clockboundd.sock
    1639491883489757000 nanoseconds since the Unix Epoch is after the current time's error bounds.
    Waiting 2 seconds...
    1639491883489757000 nanoseconds since the Unix Epoch is not after the current time's error bounds.
    

    By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

    opened by siddontang 4
  • Add support to the client uses abstract address to connect to the daemon

    Add support to the client uses abstract address to connect to the daemon

    Description of changes:

    The current implementation assumes the client connects to the daemon using file system based socket. If the client uses [an abstract socket address], it fails to send back response.

    The change allows the daemon to communicate back to the client irrespective to the type of socket it uses.

    opened by daxinc 3
  • Bump client to 0.1.1 and daemon to 0.1.2

    Bump client to 0.1.1 and daemon to 0.1.2

    Bump versions and update Cargo.lock.

    By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

    opened by dfoxfranke 2
  • Fix toctou

    Fix toctou

    Description of changes:

    The current now() API call is prone to TOCTOU (time-of-check to time-of-use) error. This adds an additional API call which accepts a callback to an execution that needs to be timestamped by the user and calculates the upper and lower bound based on that.

    pub struct TimingResult {
        /// Callback began executing no earlier than this time
        pub earliest_start : SystemTime,
        /// Callback finished executing no later than this time
        pub latest_finish : SystemTime,
        /// No less than this amount of time elapsed from when timing() was called
        /// to when it returned.
        pub min_execution_time : Duration,
        /// No more than this amount of time elapsed when the callback was invoked
        /// to when it returned.
        pub max_execution_time : Duration
    }
    

    It also returns maximum and minimum execution time of the timing API call.

    Overview of the execution steps taken by the API call

    1. User calls the `timing(f)` API 
    2. Collects the upper and lower bound at T1 
    3. Executes the callback f
    4. Collects the upper and lower bound at T2
    5. Compares duration between T1 midpoint and T2 midpoint
    6. Computes maximum and minimum duration by +/- clock frequency
    7. Returns upper bound, lower bound, min execution, maximum execution
    

    Sample output of running cargo run --example timing /run/clockboundd/clockboundd.sock

    Earliest start time for the timing request: "2022-02-21 19:43:34.530780989"
    Latest finish time for the timing request: "2022-02-21 19:43:34.552979011"
    Minimum execution duration of timing request: 51µs
    Maximum execution duration of timing request: 73µs
    

    By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

    opened by basilnsindhu 0
  • Update daemon dependencies and bump to 0.1.1

    Update daemon dependencies and bump to 0.1.1

    Bumped clock-bound-d version to 0.1.1 and ran cargo update in order to bring in chrony-candm-0.1.1 with https://github.com/aws/chrony-candm/pull/1

    By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

    opened by dfoxfranke 0
  • Fix crates.io badge to point to clock-bound-c

    Fix crates.io badge to point to clock-bound-c

    Description of changes:

    Updates the crates.io badge of clock-bound-c to point to clock-bound-c instead of clock-bound-d.

    By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

    opened by jacoblwisniewski 0
  • Inital working 0.1.0 version

    Inital working 0.1.0 version

    Description of changes:

    Includes the initial working version of ClockBound.

    By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

    opened by jacoblwisniewski 0
  • Add client functionality for periodic polling and alerting

    Add client functionality for periodic polling and alerting

    WIP while I add some example code.

    This PR adds some functionality to the client library to periodically poll the daemon and trigger a callback if the clock error bound falls above or below user-provided thresholds.

    By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

    opened by dfoxfranke 0
  • Run clock-bound-d on Docker

    Run clock-bound-d on Docker

    Hello. I would like to run clock-bound-d on Docker, but there are probably two barriers.

    1. clock-bound-d currently supports only syslog logging.

    I wrote the following Dockerfile, but this gives me an error.

    FROM rust:1.59.0-bullseye
    RUN cargo install clock-bound-d --version 0.1.1
    CMD ["clockboundd"]
    
    thread 'main' panicked at 'could not connect to syslog: Error(Initialization, State { next_error: Some(Error(Io(Os { code: 2, kind: NotFound, message: "No such file or directory" }), State { next_error: None, backtrace: InternalBacktrace })), backtrace: InternalBacktrace })', /usr/local/cargo/registry/src/github.com-1ecc6299db9ec823/clock-bound-d-0.1.1/src/main.rs:65:42
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    
    1. clock-bound-d supports only 323 port.

    When running clock-bound-d on Docker, I'm thinking of running chrony as a side car. For example, I'm thinking of using https://github.com/cturra/docker-ntp , which works with port 123. I think a workaround is possible, but it would be useful to be able to use a port other than 323.

    Are there any plans to make these two points configurable?

    opened by ohkinozomu 3
Owner
Amazon Web Services
Amazon Web Services
A set of bison skeleton files that can be used to generate a Bison grammar that is written in Rust.

rust-bison-skeleton A set of bison skeleton files that can be used to generate a Bison grammar that is written in Rust. Technically it's more like a B

Ilya Bylich 12 Dec 14, 2022
A simple to use rust package to generate or parse Twitter snowflake IDs,generate time sortable 64 bits unique ids for distributed systems

A simple to use rust package to generate or parse Twitter snowflake IDs,generate time sortable 64 bits unique ids for distributed systems (inspired from twitter snowflake)

houseme 5 Oct 6, 2022
An implementation of the SMP protocol as used in zephyr, mcuboot, mcumgr, and more.

SMP An implementation of the SMP protocol in pure Rust. This repository contains: ./mcumgr-smp: A SMP library implementation to be used in your own pr

Gessler GmbH 3 Dec 10, 2023
Generate bindings to use Rust code in Qt and QML

Rust Qt Binding Generator This code generator gets you started quickly to use Rust code from Qt and QML. In other words, it helps to create a Qt based

KDE GitHub Mirror 768 Dec 24, 2022
Rust library to generate word cloud images from text and images !

wordcloud-rs A Rust library to generate word-clouds from text and images! Example Code use std::collections::HashMap; use std::fs; use lazy_static::la

Teo Orthlieb 2 Dec 8, 2022
Generate commit messages using GPT3 based on your changes and commit history.

Commit Generate commit messages using GPT-3 based on your changes and commit history. Install You need Rust and Cargo installed on your machine. See t

Brian Le 40 Jan 3, 2023
"Philips Ambilight for desktops". A tool to generate color palettes from your desktop wallpaper and send them to Home Assistant.

Desktop Dye DesktopDye is an open source project written in Rust that allows users to have their lights paired with Home Assistant adjust to the most

Jeroen Meijer (Jay) 7 Feb 22, 2023
Toolkit for working with scripts used by REDengine in Cyberpunk 2077.

redscript Toolkit for working with scripts used by REDengine in Cyberpunk 2077. Currently includes a compiler, a decompiler and a disassembler. usage

jac3km4 268 Jan 6, 2023
Rust crate for reading SER files used in astrophotography

Rust crate for reading SER files used in astrophotography.

Andy Grove 2 Oct 4, 2021
A VtubeStudio plugin that allows iFacialMocap to stream data to the app, enabling full apple ARkit facial tracking to be used for 2D Vtuber models.

facelink_rs A VtubeStudio plugin that allows iFacialMocap to stream data to the app, enabling full apple ARkit facial tracking to be used for 2D Vtube

Slashscreen 2 May 6, 2022
Common utilities code used across Fulcrum Genomics Rust projects

fgoxide Common utilities code used across Fulcrum Genomics Rust projects. Why? There are many helper functions that are used repeatedly across project

Fulcrum Genomics 2 Nov 2, 2022
Generate short, memorable phrases for throw-away names.

Generates three-word phrases of the form intensifier-adjective-noun, just like GitHub default repo names.

null 6 Dec 25, 2021
Generate a THIRDPARTY file with all licenses in a cargo project.

cargo-bundle-licenses Bundle all third-party licenses into a single file. NOTE This tools is not a lawyer and no guarantee of correctness can be made

Seth 58 Jan 7, 2023
Generate alerts for when metrics/recordings become absent

prometheus-absent-data-alert-rule-generator prometheus-absent-data-alert-rule-generator is a tool to generate alerts for missing data in time-series t

Stile Education 5 Sep 9, 2022
Generate an HTML page based on a Notion document

Notion Generator Generate an HTML page based on a Notion document! Still a bit of a work in progress, but I am about to actually use it for some actua

null 9 Dec 14, 2022
Rust macro that uses GPT3 codex to generate code at compiletime

gpt3_macro Rust macro that uses GPT3 codex to generate code at compiletime. Just describe what you want the function to do and (optionally) define a f

Maximilian von Gaisberg 59 Dec 18, 2022
Generate enum from a trait, with converters between them

Derive macro for Rust that turns traits into enums, providing tools for calling funtions over channels

Vitaly Shukela 16 Nov 3, 2022
Generate Rust register maps (`struct`s) from SVD files

svd2rust Generate Rust register maps (structs) from SVD files This project is developed and maintained by the Tools team. Documentation API Minimum Su

Rust Embedded 518 Dec 30, 2022
📝 Generate your README.md from Rust doc comments

cargo-onedoc ?? Generate README.md from doc comments. Only write your documentation once! This crate provides a Cargo subcommand that can generate Mar

Ross MacArthur 2 Dec 14, 2022