Skip to content

Commit 05c7256

Browse files
authored
Add "dag-based consensus" (#198)
Signed-off-by: Giuliano Losa <giuliano@losa.fr>
1 parent 00eb5b4 commit 05c7256

13 files changed

Lines changed: 568 additions & 1 deletion

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ Here is a list of specs included in this repository which are validated by the C
105105
| [Condition-Based Consensus](specifications/cbc_max) | Thanh Hai Tran, Igor Konnov, Josef Widder | | | | | |
106106
| [Buffered Random Access File](specifications/braf) | Calvin Loncaric | | | || |
107107
| [Disruptor](specifications/Disruptor) | Nicholas Schultz-Møller | | | || |
108+
| [DAG-based Consensus](specifications/dag-consensus) | Giuliano Losa | | ||| |
108109

109110

110111
## Other Examples
@@ -151,7 +152,7 @@ Ideally these will be moved into this repo over time.
151152
| [Petri Nets](https://github.com/elh/petri-tlaplus) | Instantiable Petri Nets with liveness properties | Eugene Huang | | || | |
152153
| [CRDT](https://github.com/JYwellin/CRDT-TLA) | Specifying and Verifying CRDT Protocols | Ye Ji, Hengfeng Wei | | || | |
153154
| [Azure Cosmos DB](https://github.com/tlaplus/azure-cosmos-tla) | Consistency models provided by Azure Cosmos DB | Dharma Shukla, Ailidani Ailijiang, Murat Demirbas, Markus Kuppe | | ||| |
154-
| [Simple Microwave Oven](specifications/microwave) | Spec of a microwave oven | Konstantin Läufer, George K. Thiruvathukal | | | | | | |
155+
| [Simple Microwave Oven](https://github.com/lucformalmethodscourse/microwave-tla) | Spec of a microwave oven | Konstantin Läufer, George K. Thiruvathukal | | | | | | |
155156

156157
## Contributing a Spec
157158

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
----------------------------- MODULE BlockDag -----------------------------
2+
3+
(**************************************************************************************)
4+
(* In this specification we define notions on DAGs useful for DAG-based consensus *)
5+
(* protocols (which build DAGs of blocks) *)
6+
(**************************************************************************************)
7+
8+
EXTENDS FiniteSets, Sequences, Integers, Utils, Digraph, TLC
9+
10+
CONSTANTS
11+
N \* The set of all network nodes (not DAG nodes)
12+
, R \* The set of rounds
13+
, Leader(_) \* operator mapping each round to its leader
14+
15+
(**************************************************************************************)
16+
(* For our purpose of checking safety and liveness, DAG vertices just consist of a *)
17+
(* node and a round. *)
18+
(**************************************************************************************)
19+
V == N \times R \* the set of possible DAG vertices
20+
Node(v) == v[1]
21+
Round(v) == IF v = <<>> THEN 0 ELSE v[2] \* accomodates <<>> as default value
22+
23+
(**************************************************************************************)
24+
(* Next we define leader vertices: *)
25+
(**************************************************************************************)
26+
LeaderVertex(r) == IF r > 0 THEN <<Leader(r), r>> ELSE <<>>
27+
IsLeader(v) == LeaderVertex(Round(v)) = v
28+
Genesis == <<>>
29+
ASSUME IsLeader(Genesis) \* this should hold
30+
31+
(**************************************************************************************)
32+
(* OrderSet(S) arbitrarily order the members of the set S. Note that, in TLA+, *)
33+
(* `CHOOSE' is deterministic but arbitrary choice, i.e. `CHOOSE e \in S : TRUE' is *)
34+
(* always the same `e' if `S' is the same *)
35+
(**************************************************************************************)
36+
RECURSIVE OrderSet(_)
37+
OrderSet(S) == IF S = {} THEN <<>> ELSE
38+
LET e == CHOOSE e \in S : TRUE
39+
IN Append(OrderSet(S \ {e}), e)
40+
41+
(**************************************************************************************)
42+
(* PreviousLeader(dag, r) returns the leader vertex in dag whose round is the *)
43+
(* largest but smaller than r. We assume that dag contains at least the genesis *)
44+
(* vertex. *)
45+
(**************************************************************************************)
46+
PreviousLeader(dag, r) == CHOOSE l \in Vertices(dag) :
47+
/\ IsLeader(l)
48+
/\ Round(l) = Max({Round(l2) : l2 \in
49+
{l2 \in Vertices(dag) : IsLeader(l2) /\ Round(l2) < r}})
50+
51+
(**************************************************************************************)
52+
(* Linearize a DAG. In a real blockchain we should use a topological ordering, but, *)
53+
(* for the purpose of ensuring agreement, an arbitrary ordering (as provided by *)
54+
(* OrderSet) is fine. This assume a DAG where all paths end with the Genesis *)
55+
(* vertex. *)
56+
(**************************************************************************************)
57+
RECURSIVE Linearize(_, _)
58+
Linearize(dag, l) == IF Vertices(dag) = {<<>>} THEN <<>> ELSE
59+
LET dagOfL == SubDag(dag, {l})
60+
prevL == PreviousLeader(dagOfL, Round(l))
61+
dagOfPrev == SubDag(dag, {prevL})
62+
remaining == Vertices(dagOfL) \ Vertices(dagOfPrev)
63+
IN Linearize(dagOfPrev, prevL) \o OrderSet(remaining \ {l}) \o <<l>>
64+
65+
Compatible(s1, s2) == \* whether the sequence s1 is a prefix of the sequence s2, or vice versa
66+
\A i \in 1..Min({Len(s1), Len(s2)}) : s1[i] = s2[i]
67+
=========================================================================

specifications/dag-consensus/BlockDagTest.cfg

Whitespace-only changes.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
----------------------------- MODULE BlockDagTest -----------------------------
2+
3+
(**************************************************************************************)
4+
(* Tests for BlockDag operators using small concrete DAGs. *)
5+
(**************************************************************************************)
6+
7+
EXTENDS FiniteSets, Sequences, Integers, TLC
8+
9+
N == {1, 2}
10+
R == 1..3
11+
Leader(r) == CASE
12+
r = 1 -> 1
13+
[] r = 2 -> 2
14+
[] r = 3 -> 1
15+
16+
INSTANCE BlockDag WITH N <- N, R <- R, Leader <- Leader
17+
18+
v11 == <<1, 1>> \* leader
19+
v21 == <<2, 1>>
20+
v12 == <<1, 2>>
21+
v22 == <<2, 2>> \* leader
22+
v13 == <<1, 3>> \* leader
23+
v23 == <<2, 3>>
24+
25+
ASSUME TestNodeRound == Node(v12) = 1 /\ Round(v12) = 2
26+
27+
ASSUME TestLeaderVertice ==
28+
/\ LeaderVertex(1) = v11
29+
/\ LeaderVertex(2) = v22
30+
/\ LeaderVertex(3) = v13
31+
32+
ASSUME TestOrderSetPermutation ==
33+
LET SeqToSet(seq) == {seq[i] : i \in DOMAIN seq}
34+
IsPermutation(seq, s) == SeqToSet(seq) = s /\ Len(seq) = Cardinality(s)
35+
IN IsPermutation(OrderSet({v11, v21}), {v11, v21})
36+
37+
dag1 ==
38+
<< {Genesis, v11, v21, v12, v22, v13, v23},
39+
{<<v11, Genesis>>, <<v21, Genesis>>,
40+
<<v12, v21>>, <<v22, v11>>, <<v13, v22>>,
41+
<<v13, v21>>, <<v13, v12>>, <<v23, v22>>} >>
42+
43+
ASSUME TestPreviousLeader1 == PreviousLeader(dag1, 3) = v22
44+
ASSUME TestPreviousLeader2 == PreviousLeader(dag1, 2) = v11
45+
ASSUME TestPreviousLeaderBase == PreviousLeader(dag1, 1) = <<>>
46+
47+
ASSUME TestLinearize == Linearize(dag1, v13) =
48+
<<<<1, 1>>, <<2, 2>>>> \o OrderSet({<<2, 1>>, <<1, 2>>}) \o <<<<1, 3>>>>
49+
50+
=========================================================================
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
----------------------------- MODULE Digraph -----------------------------
2+
3+
(**************************************************************************************)
4+
(* A digraph is a pair consisting of a set of vertices and a set of edges *)
5+
(**************************************************************************************)
6+
7+
Vertices(digraph) == digraph[1]
8+
Edges(digraph) == digraph[2]
9+
10+
IsDigraph(digraph) ==
11+
/\ digraph = <<Vertices(digraph), Edges(digraph)>>
12+
/\ \A e \in Edges(digraph) :
13+
/\ e = <<e[1],e[2]>>
14+
/\ {e[1],e[2]} \subseteq Vertices(digraph)
15+
16+
Children(digraph, v) ==
17+
{c \in Vertices(digraph) : <<v, c>> \in Edges(digraph)}
18+
19+
(**************************************************************************************)
20+
(* Descendants(dag, vs) is the set of vertices reachable from any vertex in vs *)
21+
(**************************************************************************************)
22+
RECURSIVE Descendants(_, _)
23+
Descendants(dag, vs) == IF vs = {} THEN {} ELSE
24+
LET children == {c \in Vertices(dag) : \E v \in vs : <<v,c>> \in Edges(dag)} IN
25+
children \cup Descendants(dag, children)
26+
27+
(**************************************************************************************)
28+
(* The sub-dag reachable from the set of vertices vs: *)
29+
(**************************************************************************************)
30+
SubDag(dag, vs) ==
31+
LET vs2 == Descendants(dag, vs) \cup vs
32+
es2 == {e \in Edges(dag) : e[1] \in vs2} \* implies e[2] \in vs2
33+
IN <<vs2, es2>>
34+
35+
==========================================================================
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Formal specifications of DAG-based consensus protocols
2+
3+
Copied from [nano-o/dag-consensus](https://github.com/nano-o/dag-consensus).
4+
5+
## Block DAGs
6+
7+
[BlockDag.tla](./BlockDag.tla) defines block DAGs and how DAG-based consensus protocols linearize them.
8+
This specification should be reusable for other DAG-based consensus protocols.
9+
To run some basic tests, run `make block-dag-test`.
10+
11+
## Sailfish
12+
13+
[Sailfish.tla](./Sailfish.tla) contains a high-level formal specification modeling both the Sailfish and Sailfish++ protocols (at the level of abstraction of the specification, the differences between the protocols are not visible).
14+
15+
Sailfish is described in the paper ["Sailfish: Towards Improving the Latency of DAG-based BFT"](https://eprint.iacr.org/2024/472), S&P 2025, and Sailfish++ appears in the paper ["Optimistic, Signature-Free Reliable Broadcast and Its Applications"](https://arxiv.org/abs/2505.02761), CCS 2025.
16+
17+
To run TLC on the specification, first translate the PlusCal part to TLA+ with `make trans TLA_SPEC=Sailfish.tla` and then run `make run-tlc TLA_SPEC=TLCSailfish1.tla`. The specification `TLCSailfish1.tla` and the associated config file `TLCSailfish1.cfg` fix a concrete system size, model-checking bounds, and the properties to check (typing invariant, agreement, and liveness).
18+
19+
Have a look at the Makefile to tweak TLC options.
20+
21+
Notes:
22+
- `make trans` rewrites the TLA+ module in place after PlusCal translation.
23+
- The Makefile expects `java` and `wget` to be available to download/run `tla2tools.jar`.

0 commit comments

Comments
 (0)