Skip to content

Latest commit

 

History

History
167 lines (117 loc) · 5.68 KB

HACKING.md

File metadata and controls

167 lines (117 loc) · 5.68 KB

Hacking on TigerBeetle

Prerequisites: TigerBeetle makes use of certain fairly new technologies, such as io_uring or advanced CPU instructions for cryptography. As such, it requires a fairly modern kernel (≥ 5.6) and CPU. While at the moment only Linux is supported for production deployments, TigerBeetle also works on Windows and MacOS.

Building

git clone https://github.com/tigerbeetle/tigerbeetle.git
cd tigerbeetle
./scripts/install_zig.sh # There's a .bat version for Windows.
./zig/zig build -Drelease
./tigerbeetle --version

See the Quick Start for how to use a freshly-built TigerBeetle.

Testing

TigerBeetle has several layers of tests. The Zig unit tests can be run as:

./zig/zig build test

To run a single test, pass its name after --:

./zig/zig build test -- parse_addresses

The entry point for various "minor" fuzzers is:

./zig/zig build fuzz -- smoke

See /src/fuzz_tests.zig for the menu of available fuzzers.

Simulation Tests

To run TigerBeetle's long-running simulation, called The VOPR:

zig/zig build simulator_run

To run the VOPR using a specific seed:

zig/zig build simulator_run -- 123

The VOPR stands for The Viewstamped Operation Replicator and was inspired by the movie WarGames, by our love of fuzzing over the years, by Dropbox's Nucleus testing, and by FoundationDB's deterministic simulation testing.

The VOPR is a deterministic simulator that can fuzz many clusters of TigerBeetle servers and clients interacting through TigerBeetle's Viewstamped Replication consensus protocol, but all within a single developer machine process, with a network simulator to simulate all kinds of network faults, and with an in-memory storage simulator to simulate all kinds of storage faults, to explore and test TigerBeetle against huge state spaces in a short amount of time, by literally speeding up the passing of time within the simulation itself.

Beyond being a deterministic simulator, The VOPR also features a state checker that can hook into all the replicas, and check all their state transitions the instant they take place, using cryptographic hash chaining to prove causality and check that all interim state transitions are valid, based on any of the set of inflight client requests at the time, without divergent states, and then check for convergence to the highest state at the end of the simulation, to distinguish between correctness or liveness bugs.

Check out TigerBeetle's Viewstamped Replication Made Famous bug bounty challenge repository for more details on how to run The VOPR and interpret its output.

Hacking on Clients

Each client is built using language-specific tooling (npm, maven, dotnet, and go), and links to a native library built with Zig. The general pattern is

./zig/zig build client_lang
cd src/clients/lang
lang_package_manager test

See client/$LANG/ci.zig scripts for exact commands we use on CI to build clients.

Testing Client Libraries

Each language client is tested by a mixture of unit-tests written using language-specific test frameworks, and integration tests which run sample projects against a real tigerbeetle process. Everything is orchestrated by ci.zig script:

./zig/zig build scripts -- ci --language=go

Other Useful Commands

Build & immediately run TigerBeetle:

./zig/zig build run -- format ...

Quickly check if the code compiles without spending time to generate the binary:

./zig/zig build check

Reformat the code according to style:

./zig/zig fmt .

Run lint checks:

./zig/zig build test -- tidy

Run macro benchmark:

./zig/zig build -Drelease run -- benchmark

See comments at the top of /src/tigerbeetle/benchmark_load.zig for details of benchmarking.

Docs

Developer-oriented documentation is at /docs/about/internals/README.md

Getting In Touch

Say hello in our Slack!

Pull Requests

When submitting pull request, assign a single person to be its reviewer. Unpacking:

  • GitHub supports both "assign" and "request review". The difference between them is that "request" is "edge triggered" (it is cleared after a round of review), while "assign" is "level triggered" (it won't go away until the PR is merged or closed). We use "assign", because the reviewer is co-responsible for making sure that the PR doesn't stall, and is eventually completed.

  • Only a single person is assigned to any particular pull request, to avoid diffusion of responsibility and the bystander effect.

  • Pull request author choses the reviewer. The author ha the most context about who is the best person to request review from. When picking a reviewer, think about sharing knowledge, balancing review load, and maximizing correctness of the code.

After pull request is approved, the author makes the final call to merge by clicking "merge when ready" button on GitHub. To reduce the number of round-trips, "merge when ready" can be engaged before the review is completed: a PR will then be merged automatically once an approving review is submitted.