-
Notifications
You must be signed in to change notification settings - Fork 201
/
aba_asyn_byz.tla
160 lines (131 loc) · 5.72 KB
/
aba_asyn_byz.tla
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
------------------------------ MODULE aba_asyn_byz ------------------------------
(* An encoding of the asynchronous Byzantine consensus protocol in Fig.3 [1]:
[1] Bracha, Gabriel, and Sam Toueg. "Asynchronous consensus and broadcast protocols."
Journal of the ACM (JACM) 32.4 (1985): 824-840.
Thanh Hai Tran, Igor Konnov, Josef Widder, 2016
This file is a subject to the license that is bundled together with this package and can
be found in the file LICENSE.
*)
EXTENDS Naturals (*, FiniteSets *)
CONSTANTS N, T, F
VARIABLES nSntE, (* the number of ECHO, READY messages which are sent *)
nSntR,
nRcvdE, (* the number of ECHO, READY messages which are received *)
nRcvdR,
nByz, (* the number of Byzantine processes *)
pc (* program counters *)
ASSUME NTF == N \in Nat /\ T \in Nat /\ F \in Nat /\ (N > 3 * T) /\ (T >= F) /\ (F >= 0)
Proc == 1 .. N
Location == { "V0", "V1", "EC", "RD", "AC", "BYZ" }
vars == << nSntE, nSntR, nRcvdE, nRcvdR, nByz, pc >>
guardE == (N + T + 2) \div 2
guardR1 == T + 1
guardR2 == 2 * T + 1
(* Some processes propose 0 and others propose 1.*)
Init ==
/\ nSntE = 0 (* Neither ECHO nor READY messages are sent. *)
/\ nSntR = 0
/\ nRcvdE = [ i \in Proc |-> 0 ] (* Neither ECHO nor READY messages are received. *)
/\ nRcvdR = [ i \in Proc |-> 0 ]
/\ nByz = 0 (* No processes are faulty. *)
/\ pc \in [ Proc -> { "V0", "V1" } ]
(* All processes propose 0. *)
Init0 ==
/\ nSntE = 0
/\ nSntR = 0
/\ nRcvdE = [ i \in Proc |-> 0 ]
/\ nRcvdR = [ i \in Proc |-> 0 ]
/\ nByz = 0
/\ pc \in [ i \in Proc |-> "V0" ]
(* All processes propose 1. *)
Init1 ==
/\ nSntE = 0
/\ nSntR = 0
/\ nRcvdE = [ i \in Proc |-> 0 ]
/\ nRcvdR = [ i \in Proc |-> 0 ]
/\ nByz = 0
/\ pc \in [ i \in Proc |-> "V1" ]
(* If there are less than F Byzantine processes, process i becomes faulty. *)
(* We requite i to be in an initial state (V0 or V1) to not break the *)
(* message counting abstraction. *)
BecomeByzantine(i) ==
/\ nByz < F
/\ \/ pc[i] = "V1"
\/ pc[i] = "V0"
/\ nByz' = nByz + 1
/\ pc' = [ pc EXCEPT ![i] = "BYZ" ]
/\ UNCHANGED << nSntE, nSntR, nRcvdE, nRcvdR >>
(* Process i receives a new message. If includeByz is TRUE, then messages from both *)
(* correct and Byzantine processes are considered. Otherwise, only messages from *)
(* correct processes are considered. *)
Receive(i, includeByz) ==
\/ /\ nRcvdE[i] < nSntE + (IF includeByz THEN nByz ELSE 0)
/\ nRcvdE' = [ nRcvdE EXCEPT ![i] = nRcvdE[i] + 1 ]
/\ UNCHANGED << nSntE, nSntR, nRcvdR, nByz, pc >>
\/ /\ nRcvdR[i] < nSntR + (IF includeByz THEN nByz ELSE 0)
/\ nRcvdR' = [ nRcvdR EXCEPT ![i] = nRcvdR[i] + 1 ]
/\ UNCHANGED << nSntE, nSntR, nRcvdE, nByz, pc >>
\/ /\ UNCHANGED vars
(* Process i will send an ECHO message if it proposed 1 and did not send an ECHO message.
If process i proposed 0, did not send an ECHO message but has received greater than
(N + F) / 2 ECHO messages or (F + 1) READY messages, it will also send an ECHO messages.
*)
SendEcho(i) ==
/\ \/ pc[i] = "V1"
\/ /\ pc[i] = "V0"
/\ \/ nRcvdE[i] >= guardE
\/ nRcvdR[i] >= guardR1
/\ pc' = [ pc EXCEPT ![i] = "EC" ]
/\ nSntE' = nSntE + 1
/\ UNCHANGED << nSntR, nRcvdE, nRcvdR, nByz >>
(* If process i sent an ECHO message and has received enough ECHO or READY messages,
it will send a READY messages.
*)
SendReady(i) ==
/\ pc[i] = "EC"
/\ \/ nRcvdE[i] >= guardE
\/ nRcvdR[i] >= guardR1
/\ pc' = [ pc EXCEPT ![i] = "RD" ]
/\ nSntR' = nSntR + 1
/\ UNCHANGED << nSntE, nRcvdE, nRcvdR, nByz >>
(* If process has received READY messages from a majority of processes, it will accept. *)
Decide(i) ==
/\ pc[i] = "RD"
/\ nRcvdR[i] >= guardR2
/\ pc' = [ pc EXCEPT ![i] = "AC" ]
/\ UNCHANGED << nSntE, nSntE, nSntR, nRcvdE, nRcvdR, nByz >>
Next ==
/\ \E self \in Proc :
\/ BecomeByzantine(self)
\/ Receive(self, TRUE)
\/ SendEcho(self)
\/ SendReady(self)
\/ Decide(self)
\/ UNCHANGED vars
(* Add weak fairness condition since we want to check liveness properties. *)
Spec == Init /\ [][Next]_vars
/\ WF_vars(\E self \in Proc : \/ Receive(self, FALSE)
\/ SendEcho(self)
\/ SendReady(self)
\/ Decide(self))
Spec0 == Init0 /\ [][Next]_vars
/\ WF_vars(\E self \in Proc : \/ Receive(self, FALSE)
\/ SendEcho(self)
\/ SendReady(self)
\/ Decide(self))
TypeOK ==
/\ pc \in [ Proc -> Location ]
/\ nSntE \in 0..N
/\ nSntR \in 0..N
/\ nByz \in 0..F
/\ nRcvdE \in [ Proc -> 0..(nSntE + nByz) ]
/\ nRcvdR \in [ Proc -> 0..(nSntR + nByz) ]
Unforg_Ltl ==
(\A i \in Proc : pc[i] = "V0") => []( \A i \in Proc : pc[i] # "AC" )
Corr_Ltl ==
(\A i \in Proc : pc[i] = "V1") => <>( \E i \in Proc : pc[i] = "AC" )
Agreement_Ltl ==
[]((\E i \in Proc : pc[i] = "AC") => <>(\A i \in Proc : pc[i] = "AC" \/ pc[i] = "BYZ" ))
=============================================================================
\* Modification History
\* Last modified Fri Jul 06 15:04:01 CEST 2018 by tthai