DistAI: Data-Driven Automated Invariant Learning for Distributed Protocols
DistAI is a tool to automatically infer inductive invariants to prove the correctness of distributed protocols. It takes a simulation-learning-refinement workflow. Given a protocol, DistAI first repeatedly simulate the protocol using randomized instances. This gives a collection of simulation traces (i.e., samples). Then DistAI applies an enumeration-based learning procedure to find invariants that hold true on all the samples. Finally, DistAI uses Ivy, a theorem prover built on top of Z3 SMT solver, to refine the invariants using counterexamples until validated.
Installation
You can build DistAI from source using the installation guide install.txt
. Native installation gives the most accurate runtime numbers.
Alternatively, one can use our docker image with the guide docker_usage.md
. This image also includes I4 and FOL-IC3, the two systems DistAI compared with in the evaluation.
Usage
Top-level API
Given the name of a distributed protocol, python main.py PROTOCOL
simulates the protocol, learn the invariants and refine them. The proved protocol with correct invariants will be written to outputs/PROTOCOL/PROTOCOL_inv.ivy
python main.py two_phase_commit
Step-by-step instructions
In src-py/
, we can use python translate.py PROTOCOL
to generate the simulation script in Python from the Ivy source.
It accepts a conditional argument --min_size
for the minimum instance size (i.e., initial template size). If omitted, DistAI will infer the minimum size from the protocol.
python translate.py distributed_lock --min_size="node=2 epoch=2"
The simulation script is written to auto_samplers/
. From there, run python PROTOCOL.py
to simulate the protocol.
python database_chain_replication.py
The samples are written to traces/
, and a configuration file is generated in configs/
. Then, in src-c/
,
run ./main PROTOCOL [MAX_RETRY]
to learn and infer the invariants. MAX_RETRY
is a conditional argument indicating how many times the solver should retry (i.e., incrementing max-literal) before giving up.
./main blockchain 1
The proved protocol with correct inductive invariants attached is written to outputs/PROTOCOL/PROTOCOL_inv.ivy
. From there, one can use
ivy_check PROTOCOL_inv.ivy
to validate its correctness.
Running new protocols
To use DistAI on a new distributed protocol, simply add the Ivy file at protocols/NEW_PROTOCOL/NEW_PROTOCOL.ivy
, and make an empty directory outputs/NEW_PROTOCOL/
. Then run python main.py NEW_PROTOCOL
Note that to simulate the protocol, DistAI parses the Ivy file from scratch instead of using the Ivy compiler. The parser/translator does not support full grammar of Ivy 1.7. We are working to extend it. If you have questions please let us know.
Reproduce Figure 6
Run python tradeoff_figure.py
. The output figure is saved at tradeoff.png
Structure
-
protocols/: The 14 distributed protocols in Ivy. The mapping between protocol names in the paper and acronyms in this repository is given below.
protocol name acronym async lock server multi_lock_server chord ring maintenance chord database replication database_chain_replication decentralized lock decentralized_lock distributed lock distributed_lock hashed sharding shard leader election leader learning switch switch lock server lock_server Paxos paxos permissioned blockchain blockchain Ricart-Agrawala Ricart-Agrawala simple consensus consensus two-phase commit two_phase_commit -
src-py/: The python source codes for protocol simulation
- translate.py: parse an Ivy file and emits a Python simulation script
- translate_helper.py: provides functionality for translate.py
- ivy_parser.py: parse an Ivy expression and generates a syntax tree, used by translate.py
-
src-c/: The C++ source codes for invariant enumeration and refinement
- main.cpp: the top-level handler
- basics.h/cpp: define types and data structures (e.g., how an invariant is represented)
- preprocessing.h/cpp: reads and process the trace file and configuration file
- Solver.h/cpp: the core of DistAI. Implements template projection, invariant enumeration, and invariant projection
- InvRefiner.h/cpp: interact with Ivy to refine the invariants using counterexamples
- Helper.h/cpp: provides functionality for other files