From e3b3b3bff9871a58ee18bd420a7e247b3f4df683 Mon Sep 17 00:00:00 2001 From: Igor Konnov Date: Thu, 30 Jul 2020 15:19:09 +0200 Subject: [PATCH 1/6] moved the PR from verification to tendermint-rs --- docs/spec/tendermint-fork/Tendermint.tla | 374 +++++++++++++++++ docs/spec/tendermint-fork/Tendermint3.tla | 376 +++++++++++++++++ docs/spec/tendermint-fork/Tendermint4.tla | 392 +++++++++++++++++ docs/spec/tendermint-fork/Tendermint4n4f0.tla | 387 +++++++++++++++++ docs/spec/tendermint-fork/Tendermint4n4f1.tla | 392 +++++++++++++++++ docs/spec/tendermint-fork/Tendermint4n4f2.tla | 392 +++++++++++++++++ .../tendermint-fork/Tendermint4n5f1T3.tla | 393 ++++++++++++++++++ .../tendermint-fork/apalache-n4f1.properties | 7 + .../tendermint-fork/apalache-n4f2.properties | 7 + .../tendermint-fork/apalache-n5f1.properties | 10 + .../apalache-n5f1T3.properties | 9 + docs/spec/tendermint-fork/apalache.properties | 7 + 12 files changed, 2746 insertions(+) create mode 100644 docs/spec/tendermint-fork/Tendermint.tla create mode 100644 docs/spec/tendermint-fork/Tendermint3.tla create mode 100644 docs/spec/tendermint-fork/Tendermint4.tla create mode 100644 docs/spec/tendermint-fork/Tendermint4n4f0.tla create mode 100644 docs/spec/tendermint-fork/Tendermint4n4f1.tla create mode 100644 docs/spec/tendermint-fork/Tendermint4n4f2.tla create mode 100644 docs/spec/tendermint-fork/Tendermint4n5f1T3.tla create mode 100644 docs/spec/tendermint-fork/apalache-n4f1.properties create mode 100644 docs/spec/tendermint-fork/apalache-n4f2.properties create mode 100644 docs/spec/tendermint-fork/apalache-n5f1.properties create mode 100644 docs/spec/tendermint-fork/apalache-n5f1T3.properties create mode 100644 docs/spec/tendermint-fork/apalache.properties diff --git a/docs/spec/tendermint-fork/Tendermint.tla b/docs/spec/tendermint-fork/Tendermint.tla new file mode 100644 index 000000000..461d2e06f --- /dev/null +++ b/docs/spec/tendermint-fork/Tendermint.tla @@ -0,0 +1,374 @@ +----------------------------- MODULE Tendermint ----------------------------- +(* + A TLA+ specification of Tendermint consensus by Ethan Buchman, Jae Kwon, and Zarko Milosevic. + + For the moment, we assume the following: + + 1. Every process has the voting power of 1. + 2. Timeouts are non-deterministic (works for safety). + 3. The proposer function is non-deterministic (works for safety). + + Encoded in TLA+ by Igor Konnov. It took me 4 hours to translate the pseudo-code to TLA+. + *) + +EXTENDS Integers, FiniteSets + +CONSTANTS + PropFun, \* the proposer function + Injected \* a set of the messages injected by the faulty processes + +N == 5 \* the total number of processes: correct and faulty +T == 1 \* an upper bound on the number of Byzantine processes +F == 1 \* the number of Byzantine processes +Procs == 1..N-F +Faulty == N-F+1..N +Heights == 0..1 \* the set of consensus instances +Rounds == 0..2 \* the set of possible rounds, give a bit more freedom to the solver +ValidValues == {0, 1} \* e.g., picked by a correct process, or a faulty one +InvalidValues == {2} \* e.g., sent by a Byzantine process +Values == ValidValues \cup InvalidValues \* all values +nil == -1 + +\* these are two tresholds that are used in the algorithm +THRESHOLD1 == T + 1 +THRESHOLD2 == 2 * T + 1 + +(* APALACHE-BEGIN annotations *) +a <: b == a + +MT == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, + proposal |-> Int, validRound |-> Int, hash |-> Int] +ET == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, value |-> Int] \* processed events, "for the first time" + +ValueT == Int +RoundT == Int +TimeoutT == <> \* process, height, round +(* APALACHE-END *) + +FaultyMessages == \* the messages that can be sent by the faulty processes + ([type: {"PROPOSAL"}, src: Faulty, h: Heights, + round: Rounds, proposal: Values, validRound: Rounds \cup {-1}] <: {MT}) + \cup + ([type: {"PREVOTE"}, src: Faulty, h: Heights, round: Rounds, hash: Values] <: {MT}) + \cup + ([type: {"PRECOMMIT"}, src: Faulty, h: Heights, round: Rounds, hash: Values] <: {MT}) + +NInjected == 1 \* the number of injected faulty messages +ConstInit == + /\ PropFun \in [Heights \X Rounds -> Procs] + /\ Injected \in [1..NInjected -> FaultyMessages] + + +\* these variables are exactly as in the pseudo-code +VARIABLES h, round, step, decision, lockedValue, lockedRound, validValue, validRound + +\* book-keeping variables +VARIABLES msgsPropose, \* the propose messages broadcasted in the system, a function Heights \X Rounds -> set of messages + msgsPrevote, \* the prevote messages broadcasted in the system, a function Heights \X Rounds -> set of messages + msgsPrecommit, \* the precommit messages broadcasted in the system, a function Heights \X Rounds -> set of messages + oldEvents, \* the messages processed once, as expressed by "for the first time" + timeoutPropose, \* a set of proposed timeouts: <> + timeoutPrevote, \* a set of proposed timeouts: <> + timeoutPrecommit \* a set of proposed timeouts: <> + +\* this is needed for UNCHANGED +vars == <> + +\* A function which gives the proposer for a given round at a given height. +\* Here we use round robin. As Procs and Faulty are assigned non-deterministically, +\* it does not really matter who starts first. +Proposer(ht, rd) == PropFun[ht, rd] \*1 + ((ht + rd) % N) + +Id(v) == v + +IsValid(v) == v \in ValidValues + +MixinFaults(ht, rd, type, msgs) == + \* add the messages from the faulty processes, filtered by height, round, and type + msgs \cup {m \in {Injected[x] : x \in 1..NInjected} : m.h = ht /\ m.round = rd /\ m.type = type} + +\* here we start with StartRound(0) +Init == + /\ h = [p \in Procs |-> 0] + /\ round = [p \in Procs |-> 0] + /\ step = [p \in Procs |-> "PROPOSE"] + /\ decision = [p \in Procs |-> [ht \in Heights |-> nil]] + /\ lockedValue = [p \in Procs |-> nil] + /\ lockedRound = [p \in Procs |-> -1] + /\ validValue = [p \in Procs |-> nil] + /\ validRound = [p \in Procs |-> -1] + /\ \E v \in ValidValues: + msgsPropose = [<> \in Heights \X Rounds |-> + MixinFaults(ht, rd, "PROPOSAL", + IF ht = 0 /\ rd = 0 + THEN {[type |-> "PROPOSAL", src |-> Proposer(0, 0), h |-> 0, round |-> 0, + proposal |-> v, validRound |-> -1] <: MT} + ELSE {} <: {MT})] \* no initial messages in other rounds + /\ msgsPrevote = [<> \in Heights \X Rounds |-> MixinFaults(ht, rd, "PREVOTE", {} <: {MT})] + /\ msgsPrecommit = [<> \in Heights \X Rounds |-> MixinFaults(ht, rd, "PRECOMMIT", {} <: {MT})] + /\ oldEvents = {} <: {ET} + /\ timeoutPropose = { <> : p \in Procs \ {Proposer(0, 0)}} + /\ timeoutPrevote = {} <: {TimeoutT} \* no PREVOTE timeouts + /\ timeoutPrecommit = {} <: {TimeoutT} \* no PRECOMMIT timeouts + +\* lines 22-27 +UponProposalInPropose(p) == + \E v \in Values: + /\ step[p] = "PROPOSE" \* line 22 + /\ ([type |-> "PROPOSAL", src |-> Proposer(h[p], round[p]), h |-> h[p], + round |-> round[p], proposal |-> v, validRound |-> -1] <: MT) \in msgsPropose[h[p], round[p]] \* line 22 + /\ LET isGood == IsValid(v) /\ (lockedRound[p] = -1 \/ lockedValue[p] = v) IN \* line 23 + LET newMsgs == ({[type |-> "PREVOTE", src |-> p, h |-> h[p], + round |-> round[p], hash |-> IF isGood THEN Id(v) ELSE nil] <: MT}) + IN \* lines 24-26 + msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = + msgsPrevote[h[p], round[p]] \cup newMsgs] + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 28-33 +UponProposalInProposeAndPrevote(p) == + \E v \in Values, vr \in Rounds: + /\ step[p] = "PROPOSE" /\ 0 <= vr /\ vr < round[p] \* line 28, the while part + /\ ([type |-> "PROPOSAL", src |-> Proposer(h[p], round[p]), h |-> h[p], + round |-> round[p], proposal |-> v, validRound |-> vr] <: MT) \in msgsPropose[h[p], round[p]] \* line 28 + /\ LET PV == { m \in msgsPrevote[h[p], vr]: m.hash = Id(v) } IN + Cardinality(PV) >= THRESHOLD2 \* line 28 + /\ LET isGood == IsValid(v) /\ (lockedRound[p] <= vr \/ lockedValue[p] = v) IN \* line 29 + LET newMsgs == ({[type |-> "PREVOTE", src |-> p, h |-> h[p], + round |-> round[p], hash |-> IF isGood THEN Id(v) ELSE nil] <: MT}) + IN \* lines 30-32 + msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = + msgsPrevote[h[p], round[p]] \cup newMsgs] + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 34-35 +UponPrevoteFirstTime(p) == + /\ step[p] = "PREVOTE" \* line 34 + /\ Cardinality(msgsPrevote[h[p], round[p]]) >= THRESHOLD2 \* line 34 + /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], round |-> round[p], value |-> nil] IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* process it only once + /\ timeoutPrevote' = timeoutPrevote \cup {<>} \* line 35 + /\ UNCHANGED <> + +\* lines 36-46 +UponProposalInPrevoteOrCommitAndPrevote(p) == + \E v \in ValidValues, vr \in Rounds \cup {-1}: + /\ step[p] \in {"PREVOTE", "PRECOMMIT"} \* line 36 + /\ ([type |-> "PROPOSAL", src |-> Proposer(h[p], round[p]), h |-> h[p], + round |-> round[p], proposal |-> v, validRound |-> vr] <: MT) \in msgsPropose[h[p], round[p]] \* line 36 + /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], round |-> round[p], value |-> Id(v)] IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* record that it should not happen again + /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = Id(v) } IN + Cardinality(PV) >= THRESHOLD2 \* line 36 + /\ lockedValue' = + IF step[p] = "PREVOTE" + THEN [lockedValue EXCEPT ![p] = v] \* line 38 + ELSE lockedValue \* else of line 37 + /\ lockedRound' = + IF step[p] = "PREVOTE" + THEN [lockedRound EXCEPT ![p] = round[p]] \* line 39 + ELSE lockedRound \* else of line 37 + /\ LET newMsgs == + IF step[p] = "PREVOTE" + THEN {[type |-> "PRECOMMIT", src |-> p, h |-> h[p], round |-> round[p], hash |-> Id(v)] <: MT} \* line 40 + ELSE {} <: {MT} + IN \* else of line 37 + msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = + msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 40, or else of 37 + /\ step' = IF step[p] = "PREVOTE" THEN [step EXCEPT ![p] = "PRECOMMIT"] ELSE step \* line 41 + /\ validValue' = [validValue EXCEPT ![p] = v] \* line 42 + /\ validRound' = [validRound EXCEPT ![p] = round[p]] \* line 43 + /\ UNCHANGED <> + +\* Apparently, this action is needed to deal with a value proposed by a Byzantine process +\* This action is particularly hard for the model checker +\* lines 44-46 +UponPrevoteNil(p) == + /\ step[p] = "PREVOTE" \* line 44 + /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = nil } IN + Cardinality(PV) >= THRESHOLD2 \* line 34 + /\ step' = [step EXCEPT ![p] = "PRECOMMIT"] + /\ LET newMsgs == ({[type |-> "PRECOMMIT", src |-> p, h |-> h[p], + round |-> round[p], hash |-> nil] <: MT}) \* line 45 + IN + msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = + msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 45 + /\ UNCHANGED <> + +\* lines 47-48 +UponPrecommitFirstTime(p) == + /\ Cardinality(msgsPrecommit[h[p], round[p]]) >= THRESHOLD2 \* line 47 + /\ LET event == [type |-> "PRECOMMIT", src |-> p, h |-> h[p], round |-> round[p], value |-> nil] IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* process it only once + /\ timeoutPrecommit' = timeoutPrecommit \cup {<>} \* line 48 + /\ UNCHANGED <> + +\* lines 11-21 +StartRound(p, ht, r) == + /\ round' = [round EXCEPT ![p] = r] + /\ step' = [step EXCEPT ![p] = "PROPOSE"] + /\ \E v \in ValidValues: \* lines 14-21 + LET proposal == IF validValue[p] /= nil THEN validValue[p] ELSE v IN + LET newMsgs == + IF p = Proposer(ht, r) + THEN {[type |-> "PROPOSAL", src |-> p, h |-> ht, round |-> r, + proposal |-> proposal, validRound |-> validRound[p]] <: MT} + ELSE {} <: {MT} + IN + msgsPropose' = [msgsPropose EXCEPT ![ht, r] = + msgsPropose[ht, r] \cup newMsgs] \* line 19 + /\ LET newTimeouts == \* line 21 + IF p = Proposer(ht, r) + THEN {} <: {TimeoutT} \* no new timeouts + ELSE { <> } + IN + timeoutPropose' = timeoutPropose \cup newTimeouts + +\* lines 49-54 +UponProposalInPrecommitNoDecision(p) == + /\ h[p] + 1 \in Heights + \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, + \* BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING + /\ decision[p][h[p]] = nil \* line 49 + /\ \E v \in ValidValues (* line 50*) , r \in Rounds, vr \in Rounds \cup {-1}: + /\ ([type |-> "PROPOSAL", src |-> Proposer(h[p], r), h |-> h[p], + round |-> r, proposal |-> v, validRound |-> vr] <: MT) \in msgsPropose[h[p], r] \* line 49 + /\ LET PV == { m \in msgsPrecommit[h[p], r]: m.hash = Id(v) } IN + Cardinality(PV) >= THRESHOLD2 \* line 49 + /\ decision' = [decision EXCEPT ![p][h[p]] = v] \* update the decision, line 51 + /\ h' = [h EXCEPT ![p] = h[p] + 1] \* line 52 + \* line 53 + /\ lockedRound' = [lockedRound EXCEPT ![p] = -1] + /\ lockedValue' = [lockedValue EXCEPT ![p] = nil] + /\ validRound' = [validRound EXCEPT ![p] = -1] + /\ validValue' = [validValue EXCEPT ![p] = nil] + \* What does it mean to reset the message buffer? Do it for one process only? + /\ StartRound(p, h[p] + 1, 0) + /\ UNCHANGED <> + +\* lines 55-56 +UponCatchupRound(p) == + \E r \in Rounds: + /\ r > round[p] + /\ LET PV == msgsPropose[h[p], r] \cup msgsPrevote[h[p], r] \cup msgsPrecommit[h[p], r] IN + Cardinality(PV) >= THRESHOLD1 \* line 55 + /\ StartRound(p, h[p], r) + /\ UNCHANGED <> + +\* lines 57-60 +OnTimeoutPropose(p) == + \E tm \in timeoutPropose: \* a timeout occurs + /\ tm[1] = p + /\ timeoutPropose' = timeoutPropose \ {tm} \* remove from the future timeouts + /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PROPOSE" IN + /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PREVOTE"] ELSE step \* line 60 + /\ LET newMsgs == + IF UpdateNeeded + THEN {[type |-> "PREVOTE", src |-> tm[1], h |-> tm[2], round |-> tm[3], hash |-> nil] <: MT} \* line 59 + ELSE {} <: {MT} \* else of line 58 + IN \* line 59, or else of 58 + msgsPrevote' = [msgsPrevote EXCEPT ![tm[2], tm[3]] = + msgsPrevote[tm[2], tm[3]] \cup newMsgs] + /\ UNCHANGED <> + +\* lines 61-64 +OnTimeoutPrevote(p) == + \E tm \in timeoutPrevote: \* a timeout occurs + /\ tm[1] = p + /\ timeoutPrevote' = timeoutPrevote \ {tm} \* remove from the future timeouts + /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PREVOTE" IN + /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PRECOMMIT"] ELSE step \* line 64 + /\ LET newMsgs == + IF UpdateNeeded + THEN {[type |-> "PRECOMMIT", src |-> tm[1], h |-> tm[2], round |-> tm[3], hash |-> nil] <: MT} \* line 63 + ELSE {} <: {MT} \* else of line 62 + IN \* line 63, or else of 62 + msgsPrecommit' = [msgsPrecommit EXCEPT ![tm[2], tm[3]] = + msgsPrecommit[tm[2], tm[3]] \cup newMsgs] + /\ UNCHANGED <> + +\* lines 65-67 +OnTimeoutPrecommitOutside(p) == + \E tm \in timeoutPrecommit: \* a timeout occurs + /\ tm[1] = p + /\ (tm[2] /= h[p] \/ tm[3] /= round[p]) \* but we are in another round or height + /\ timeoutPrecommit' = timeoutPrecommit \ {tm} \* remove from the future timeouts + /\ UNCHANGED <> + +\* lines 65-67 +OnTimeoutPrecommitInside(p) == + /\ round[p] + 1 \in Rounds + \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, + \* BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING + /\ <> \in timeoutPrecommit \* the timeout occurs for the current round and height + /\ timeoutPrecommit' = timeoutPrecommit \ {<>} \* remove from the future timeouts + /\ StartRound(p, h[p], round[p] + 1) + /\ UNCHANGED <> + + +Next == + \/ \E p \in Procs: + \/ UponProposalInPropose(p) + \/ UponProposalInProposeAndPrevote(p) + \/ UponPrevoteFirstTime(p) + \/ UponProposalInPrevoteOrCommitAndPrevote(p) + \/ UponPrevoteNil(p) + \/ UponPrecommitFirstTime(p) + \/ UponProposalInPrecommitNoDecision(p) + \/ UponCatchupRound(p) + \/ OnTimeoutPropose(p) + \/ OnTimeoutPrevote(p) + \/ OnTimeoutPrecommitOutside(p) + \/ OnTimeoutPrecommitInside(p) + \* a safeguard to prevent deadlocks when the algorithm goes to further heights or rounds + \*\/ UNCHANGED vars + +\* safety +Agreement == + \A p, q \in Procs, ht \in Heights: + decision[p][ht] = nil \/ decision[q][ht] = nil \/ decision[p][ht] = decision[q][ht] + +\* simple reachability properties to make sure that the algorithm is doing anything useful +NoDecision == \A p \in Procs, ht \in Heights: decision[p][ht] = nil + +NoPrecommit == \A p \in Procs: step[p] /= "PRECOMMIT" + +NoTwoLockedValues == + \A p, q \in Procs: + h[p] = h[q] => lockedValue[p] = nil \/ lockedValue[q] = nil \/ lockedValue[p] = lockedValue[q] + +NoTwoLockedRounds == + \A p, q \in Procs: + h[p] = h[q] => lockedRound[p] = -1 \/ lockedRound[q] = -1 \/ lockedRound[p] = lockedRound[q] + + +============================================================================= +\* Modification History +\* Last modified Mon Sep 16 15:00:22 CEST 2019 by igor +\* Created Fri Mar 15 10:30:17 CET 2019 by igor diff --git a/docs/spec/tendermint-fork/Tendermint3.tla b/docs/spec/tendermint-fork/Tendermint3.tla new file mode 100644 index 000000000..ea88283d1 --- /dev/null +++ b/docs/spec/tendermint-fork/Tendermint3.tla @@ -0,0 +1,376 @@ +----------------------------- MODULE Tendermint3 ----------------------------- +(* + A TLA+ specification of Tendermint consensus by Ethan Buchman, Jae Kwon, and Zarko Milosevic. + + For the moment, we assume the following: + + 1. Every process has the voting power of 1. + 2. Timeouts are non-deterministic (works for safety). + 3. The proposer function is non-deterministic (works for safety). + + Encoded in TLA+ by Igor Konnov. It took me 4 hours to translate the pseudo-code to TLA+. + + Version 3: assuming that f = 1, + using AtLeast2(S) and AtLeast3(s) instead of + Cardinality(S) >= f + 1 and Cardinality(S) >= 2f + 1 + *) + +EXTENDS Integers, FiniteSets + +CONSTANTS + PropFun, \* the proposer function + Injected \* a set of the messages injected by the faulty processes + +N == 4 \* the total number of processes: correct and faulty +T == 1 \* an upper bound on the number of Byzantine processes +F == 0 \* the number of Byzantine processes +Procs == 1..N-F +Faulty == N-F+1..N +Heights == 0..1 \* the set of consensus instances +Rounds == 0..2 \* the set of possible rounds, give a bit more freedom to the solver +ValidValues == {0, 1} \* e.g., picked by a correct process, or a faulty one +InvalidValues == {2} \* e.g., sent by a Byzantine process +Values == ValidValues \cup InvalidValues \* all values +nil == -1 + +\* these are two tresholds that are used in the algorithm +THRESHOLD1 == T + 1 +THRESHOLD2 == 2 * T + 1 + +(* APALACHE-BEGIN annotations *) +a <: b == a + +MT == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, + proposal |-> Int, validRound |-> Int, hash |-> Int] +ET == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, value |-> Int] \* processed events, "for the first time" + +\* this is an optimization, in order to avoid cardinality constraints +AtLeast2(S) == \E x, y \in S: x /= y +AtLeast3(S) == \E x, y, z \in S: x /= y /\ x /= z /\ y /= z + +ValueT == Int +RoundT == Int +TimeoutT == <> \* process, height, round +(* APALACHE-END *) + +FaultyMessages == \* the messages that can be sent by the faulty processes + ([type: {"PROPOSAL"}, src: Faulty, h: Heights, + round: Rounds, proposal: Values, validRound: Rounds \cup {-1}] <: {MT}) + \cup + ([type: {"PREVOTE"}, src: Faulty, h: Heights, round: Rounds, hash: Values] <: {MT}) + \cup + ([type: {"PRECOMMIT"}, src: Faulty, h: Heights, round: Rounds, hash: Values] <: {MT}) + +NInjected == 0 \* the number of injected faulty messages +ConstInit == + /\ PropFun \in [Heights \X Rounds -> Procs] + /\ Injected \in [1..NInjected -> FaultyMessages] + + +\* these variables are exactly as in the pseudo-code +VARIABLES h, round, step, decision, lockedValue, lockedRound, validValue, validRound + +\* book-keeping variables +VARIABLES msgsPropose, \* the propose messages broadcasted in the system, a function Heights \X Rounds -> set of messages + msgsPrevote, \* the prevote messages broadcasted in the system, a function Heights \X Rounds -> set of messages + msgsPrecommit, \* the precommit messages broadcasted in the system, a function Heights \X Rounds -> set of messages + oldEvents, \* the messages processed once, as expressed by "for the first time" + timeoutPropose, \* a set of proposed timeouts: <> + timeoutPrevote, \* a set of proposed timeouts: <> + timeoutPrecommit \* a set of proposed timeouts: <> + +\* this is needed for UNCHANGED +vars == <> + +\* A function which gives the proposer for a given round at a given height. +\* Here we use round robin. As Procs and Faulty are assigned non-deterministically, +\* it does not really matter who starts first. +Proposer(ht, rd) == PropFun[ht, rd] \*1 + ((ht + rd) % N) + +Id(v) == v + +IsValid(v) == v \in ValidValues + +MixinFaults(ht, rd, type, msgs) == + \* add the messages from the faulty processes, filtered by height, round, and type + msgs \cup {m \in {Injected[x] : x \in 1..NInjected} : m.h = ht /\ m.round = rd /\ m.type = type} + +\* here we start with StartRound(0) +Init == + /\ h = [p \in Procs |-> 0] + /\ round = [p \in Procs |-> 0] + /\ step = [p \in Procs |-> "PROPOSE"] + /\ decision = [p \in Procs |-> [ht \in Heights |-> nil]] + /\ lockedValue = [p \in Procs |-> nil] + /\ lockedRound = [p \in Procs |-> -1] + /\ validValue = [p \in Procs |-> nil] + /\ validRound = [p \in Procs |-> -1] + /\ \E v \in ValidValues: + msgsPropose = [<> \in Heights \X Rounds |-> + MixinFaults(ht, rd, "PROPOSAL", + IF ht = 0 /\ rd = 0 + THEN {[type |-> "PROPOSAL", src |-> Proposer(0, 0), h |-> 0, round |-> 0, proposal |-> v, validRound |-> -1] <: MT} + ELSE {} <: {MT})] \* no initial messages in other rounds + /\ msgsPrevote = [<> \in Heights \X Rounds |-> MixinFaults(ht, rd, "PREVOTE", {} <: {MT})] + /\ msgsPrecommit = [<> \in Heights \X Rounds |-> MixinFaults(ht, rd, "PRECOMMIT", {} <: {MT})] + /\ oldEvents = {} <: {ET} + /\ timeoutPropose = { <> : p \in Procs \ {Proposer(0, 0)}} + /\ timeoutPrevote = {} <: {TimeoutT} \* no PREVOTE timeouts + /\ timeoutPrecommit = {} <: {TimeoutT} \* no PRECOMMIT timeouts + +\* lines 22-27 +UponProposalInPropose(p) == + \E v \in Values: + /\ step[p] = "PROPOSE" \* line 22 + /\ ([type |-> "PROPOSAL", src |-> Proposer(h[p], round[p]), h |-> h[p], + round |-> round[p], proposal |-> v, validRound |-> -1] <: MT) \in msgsPropose[h[p], round[p]] \* line 22 + /\ LET isGood == IsValid(v) /\ (lockedRound[p] = -1 \/ lockedValue[p] = v) IN \* line 23 + LET newMsgs == ({[type |-> "PREVOTE", src |-> p, h |-> h[p], + round |-> round[p], hash |-> IF isGood THEN Id(v) ELSE nil] <: MT}) + IN \* lines 24-26 + msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = + msgsPrevote[h[p], round[p]] \cup newMsgs] + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 28-33 +UponProposalInProposeAndPrevote(p) == + \E v \in Values, vr \in Rounds: + /\ step[p] = "PROPOSE" /\ 0 <= vr /\ vr < round[p] \* line 28, the while part + /\ ([type |-> "PROPOSAL", src |-> Proposer(h[p], round[p]), h |-> h[p], + round |-> round[p], proposal |-> v, validRound |-> vr] <: MT) \in msgsPropose[h[p], round[p]] \* line 28 + /\ LET PV == { m \in msgsPrevote[h[p], vr]: m.hash = Id(v) } IN + AtLeast3(PV) \* line 28 + /\ LET isGood == IsValid(v) /\ (lockedRound[p] <= vr \/ lockedValue[p] = v) IN \* line 29 + LET newMsgs == ({[type |-> "PREVOTE", src |-> p, h |-> h[p], + round |-> round[p], hash |-> IF isGood THEN Id(v) ELSE nil] <: MT}) + IN \* lines 30-32 + msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = + msgsPrevote[h[p], round[p]] \cup newMsgs] + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 34-35 +UponPrevoteFirstTime(p) == + /\ step[p] = "PREVOTE" \* line 34 + /\ AtLeast3(msgsPrevote[h[p], round[p]]) \* line 34 + /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], round |-> round[p], value |-> nil] IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* process it only once + /\ timeoutPrevote' = timeoutPrevote \cup {<>} \* line 35 + /\ UNCHANGED <> + +\* lines 36-46 +UponProposalInPrevoteOrCommitAndPrevote(p) == + \E v \in ValidValues, vr \in Rounds \cup {-1}: + /\ step[p] \in {"PREVOTE", "PRECOMMIT"} \* line 36 + /\ ([type |-> "PROPOSAL", src |-> Proposer(h[p], round[p]), h |-> h[p], + round |-> round[p], proposal |-> v, validRound |-> vr] <: MT) \in msgsPropose[h[p], round[p]] \* line 36 + /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], round |-> round[p], value |-> Id(v)] IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* record that it should not happen again + /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = Id(v) } IN + AtLeast3(PV) \* line 36 + /\ lockedValue' = + IF step[p] = "PREVOTE" + THEN [lockedValue EXCEPT ![p] = v] \* line 38 + ELSE lockedValue \* else of line 37 + /\ lockedRound' = + IF step[p] = "PREVOTE" + THEN [lockedRound EXCEPT ![p] = round[p]] \* line 39 + ELSE lockedRound \* else of line 37 + /\ LET newMsgs == + IF step[p] = "PREVOTE" + THEN {[type |-> "PRECOMMIT", src |-> p, h |-> h[p], round |-> round[p], hash |-> Id(v)] <: MT} \* line 40 + ELSE {} <: {MT} + IN \* else of line 37 + msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = + msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 40, or else of 37 + /\ step' = IF step[p] = "PREVOTE" THEN [step EXCEPT ![p] = "PRECOMMIT"] ELSE step \* line 41 + /\ validValue' = [validValue EXCEPT ![p] = v] \* line 42 + /\ validRound' = [validRound EXCEPT ![p] = round[p]] \* line 43 + /\ UNCHANGED <> + +\* Apparently, this action is needed to deal with a value proposed by a Byzantine process +\* lines 44-46 +UponPrevoteNil(p) == + /\ step[p] = "PREVOTE" \* line 44 + /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = nil } IN + AtLeast3(PV) \* line 34 + /\ step' = [step EXCEPT ![p] = "PRECOMMIT"] + /\ LET newMsgs == ({[type |-> "PRECOMMIT", src |-> p, h |-> h[p], + round |-> round[p], hash |-> nil] <: MT}) \* line 45 + IN + msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = + msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 45 + /\ UNCHANGED <> + +\* lines 47-48 +UponPrecommitFirstTime(p) == + /\ AtLeast3(msgsPrecommit[h[p], round[p]]) \* line 47 + /\ LET event == [type |-> "PRECOMMIT", src |-> p, h |-> h[p], round |-> round[p], value |-> nil] IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* process it only once + /\ timeoutPrecommit' = timeoutPrecommit \cup {<>} \* line 48 + /\ UNCHANGED <> + +\* lines 11-21 +StartRound(p, ht, r) == + /\ round' = [round EXCEPT ![p] = r] + /\ step' = [step EXCEPT ![p] = "PROPOSE"] + /\ \E v \in ValidValues: \* lines 14-21 + LET proposal == IF validValue[p] /= nil THEN validValue[p] ELSE v IN + LET newMsgs == + IF p = Proposer(ht, r) + THEN {[type |-> "PROPOSAL", src |-> p, h |-> ht, round |-> r, + proposal |-> proposal, validRound |-> validRound[p]] <: MT} + ELSE {} <: {MT} + IN + msgsPropose' = [msgsPropose EXCEPT ![ht, r] = + msgsPropose[ht, r] \cup newMsgs] \* line 19 + /\ LET newTimeouts == \* line 21 + IF p = Proposer(ht, r) + THEN {} <: {TimeoutT} \* no new timeouts + ELSE { <> } + IN + timeoutPropose' = timeoutPropose \cup newTimeouts + +\* lines 49-54 +UponProposalInPrecommitNoDecision(p) == + /\ h[p] + 1 \in Heights + \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING + /\ decision[p][h[p]] = nil \* line 49 + /\ \E v \in ValidValues (* line 50*) , r \in Rounds, vr \in Rounds \cup {-1}: + /\ ([type |-> "PROPOSAL", src |-> Proposer(h[p], r), h |-> h[p], + round |-> r, proposal |-> v, validRound |-> vr] <: MT) \in msgsPropose[h[p], r] \* line 49 + /\ LET PV == { m \in msgsPrecommit[h[p], r]: m.hash = Id(v) } IN + AtLeast3(PV) \* line 49 + /\ decision' = [decision EXCEPT ![p][h[p]] = v] \* update the decision, line 51 + /\ h' = [h EXCEPT ![p] = h[p] + 1] \* line 52 + \* line 53 + /\ lockedRound' = [lockedRound EXCEPT ![p] = -1] + /\ lockedValue' = [lockedValue EXCEPT ![p] = nil] + /\ validRound' = [validRound EXCEPT ![p] = -1] + /\ validValue' = [validValue EXCEPT ![p] = nil] + \* What does it mean to reset the message buffer? Do it for one process only? + /\ StartRound(p, h[p] + 1, 0) + /\ UNCHANGED <> + +\* lines 55-56 +UponCatchupRound(p) == + \E r \in Rounds: + /\ r > round[p] + /\ LET PV == msgsPropose[h[p], r] \cup msgsPrevote[h[p], r] \cup msgsPrecommit[h[p], r] IN + AtLeast2(PV) \* line 55 + /\ StartRound(p, h[p], r) + /\ UNCHANGED <> + +\* lines 57-60 +OnTimeoutPropose(p) == + \E tm \in timeoutPropose: \* a timeout occurs + /\ tm[1] = p + /\ timeoutPropose' = timeoutPropose \ {tm} \* remove from the future timeouts + /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PROPOSE" IN + /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PREVOTE"] ELSE step \* line 60 + /\ LET newMsgs == + IF UpdateNeeded + THEN {[type |-> "PREVOTE", src |-> tm[1], h |-> tm[2], round |-> tm[3], hash |-> nil] <: MT} \* line 59 + ELSE {} <: {MT} \* else of line 58 + IN \* line 59, or else of 58 + msgsPrevote' = [msgsPrevote EXCEPT ![tm[2], tm[3]] = + msgsPrevote[tm[2], tm[3]] \cup newMsgs] + /\ UNCHANGED <> + +\* lines 61-64 +OnTimeoutPrevote(p) == + \E tm \in timeoutPrevote: \* a timeout occurs + /\ tm[1] = p + /\ timeoutPrevote' = timeoutPrevote \ {tm} \* remove from the future timeouts + /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PREVOTE" IN + /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PRECOMMIT"] ELSE step \* line 64 + /\ LET newMsgs == + IF UpdateNeeded + THEN {[type |-> "PRECOMMIT", src |-> tm[1], h |-> tm[2], round |-> tm[3], hash |-> nil] <: MT} \* line 63 + ELSE {} <: {MT} \* else of line 62 + IN \* line 63, or else of 62 + msgsPrecommit' = [msgsPrecommit EXCEPT ![tm[2], tm[3]] = + msgsPrecommit[tm[2], tm[3]] \cup newMsgs] + /\ UNCHANGED <> + +\* lines 65-67 +OnTimeoutPrecommitOutside(p) == + \E tm \in timeoutPrecommit: \* a timeout occurs + /\ tm[1] = p + /\ (tm[2] /= h[p] \/ tm[3] /= round[p]) \* but we are in another round or height + /\ timeoutPrecommit' = timeoutPrecommit \ {tm} \* remove from the future timeouts + /\ UNCHANGED <> + +\* lines 65-67 +OnTimeoutPrecommitInside(p) == + /\ round[p] + 1 \in Rounds + \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING + /\ <> \in timeoutPrecommit \* the timeout occurs for the current round and height + /\ timeoutPrecommit' = timeoutPrecommit \ {<>} \* remove from the future timeouts + /\ StartRound(p, h[p], round[p] + 1) + /\ UNCHANGED <> + + +Next == + \/ \E p \in Procs: + \/ UponProposalInPropose(p) + \/ UponProposalInProposeAndPrevote(p) + \/ UponPrevoteFirstTime(p) + \/ UponProposalInPrevoteOrCommitAndPrevote(p) + \/ UponPrevoteNil(p) \* FIXME: disabled for model checking + \/ UponPrecommitFirstTime(p) + \/ UponProposalInPrecommitNoDecision(p) + \/ UponCatchupRound(p) + \/ OnTimeoutPropose(p) + \/ OnTimeoutPrevote(p) + \/ OnTimeoutPrecommitOutside(p) + \/ OnTimeoutPrecommitInside(p) + \* a safeguard to prevent deadlocks when the algorithm goes to further heights or rounds + \*\/ UNCHANGED vars + +\* safety +Agreement == + \A p, q \in Procs, ht \in Heights: + decision[p][ht] = nil \/ decision[q][ht] = nil \/ decision[p][ht] = decision[q][ht] + +\* simple reachability properties to make sure that the algorithm is doing anything useful +NoDecision == \A p \in Procs, ht \in Heights: decision[p][ht] = nil + +NoPrecommit == \A p \in Procs: step[p] /= "PRECOMMIT" + +NoTwoLockedValues == + \A p, q \in Procs: + h[p] = h[q] => lockedValue[p] = nil \/ lockedValue[q] = nil \/ lockedValue[p] = lockedValue[q] + +NoTwoLockedRounds == + \A p, q \in Procs: + h[p] = h[q] => lockedRound[p] = -1 \/ lockedRound[q] = -1 \/ lockedRound[p] = lockedRound[q] + + +============================================================================= +\* Modification History +\* Last modified Fri Mar 22 08:57:10 CET 2019 by igor +\* Created Fri Mar 15 10:30:17 CET 2019 by igor diff --git a/docs/spec/tendermint-fork/Tendermint4.tla b/docs/spec/tendermint-fork/Tendermint4.tla new file mode 100644 index 000000000..87b03207a --- /dev/null +++ b/docs/spec/tendermint-fork/Tendermint4.tla @@ -0,0 +1,392 @@ +----------------------------- MODULE Tendermint4 ----------------------------- +(* + A TLA+ specification by Igor Konnov + of Tendermint consensus by Ethan Buchman, Jae Kwon, and Zarko Milosevic. + + For the moment, we assume the following: + + 1. Every process has the voting power of 1 (this seems to be complete). + 2. Timeouts are non-deterministic (works for safety). + 3. The proposer function is completely non-deterministic (works for safety). + + It took me 4 hours to translate the pseudo-code to TLA+. + Then it took me several days to make it more efficient for the model checker. + + Version 3: assuming that f = 1, + using AtLeastT1(S) and AtLeastT2(s) instead of + Cardinality(S) >= f + 1 and Cardinality(S) >= 2f + 1 + + Version 4: simplified record types, as we are using separate variables + for different message types and different indices for heights and rounds. + Injecting all Byzantine messages in the initial states. + *) + +EXTENDS Integers, FiniteSets + +CONSTANTS PropFun \* the proposer function + +N == 5 \* the total number of processes: correct and faulty +T == 1 \* an upper bound on the number of Byzantine processes +F == 1 \* the number of Byzantine processes +Procs == 1..N-F +Faulty == N-F+1..N +Heights == 0..1 \* the set of consensus instances +Rounds == 0..2 \* the set of possible rounds, give a bit more freedom to the solver +ValidValues == {0, 1} \* e.g., picked by a correct process, or a faulty one +InvalidValues == {2} \* e.g., sent by a Byzantine process +Values == ValidValues \cup InvalidValues \* all values +nil == -1 + +\* these are two tresholds that are used in the algorithm +THRESHOLD1 == T + 1 +THRESHOLD2 == 2 * T + 1 + +(* APALACHE-BEGIN annotations *) +a <: b == a + +MT == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, + proposal |-> Int, validRound |-> Int, hash |-> Int] +ProposalT == [src |-> Int, proposal |-> Int, validRound |-> Int] +PrevoteT == [src |-> Int, hash |-> Int] +PrecommitT == PrevoteT +ET == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, value |-> Int] \* processed events, "for the first time" + +\* This is an optimization, in order to avoid cardinality constraints +\* If T is different from 1, use the general operators: +\*AtLeastT1(S) == Cardinality(S) >= THRESHOLD1 +\*AtLeastT2(S) == Cardinality(S) >= THRESHOLD2 +AtLeastT1(S) == \E x, y \in S: x /= y +AtLeastT2(S) == \E x, y, z \in S: x /= y /\ x /= z /\ y /= z + +ValueT == Int +RoundT == Int +TimeoutT == <> \* process, height, round +(* APALACHE-END *) + +FaultyProposals == + [src: Faulty, proposal: Values, validRound: Rounds \cup {-1}] + +FaultyPrevotes == [src: Faulty, hash: Values] + +FaultyPrecommits == [src: Faulty, hash: Values] + +ConstInit == PropFun \in [Heights \X Rounds -> Procs] + + +\* these variables are exactly as in the pseudo-code +VARIABLES h, round, step, decision, lockedValue, lockedRound, validValue, validRound + +\* book-keeping variables +VARIABLES msgsPropose, \* the propose messages broadcasted in the system, a function Heights \X Rounds -> set of messages + msgsPrevote, \* the prevote messages broadcasted in the system, a function Heights \X Rounds -> set of messages + msgsPrecommit, \* the precommit messages broadcasted in the system, a function Heights \X Rounds -> set of messages + oldEvents, \* the messages processed once, as expressed by "for the first time" + timeoutPropose, \* a set of proposed timeouts: <> + timeoutPrevote, \* a set of proposed timeouts: <> + timeoutPrecommit \* a set of proposed timeouts: <> + +\* this is needed for UNCHANGED +vars == <> + +\* A function which gives the proposer for a given round at a given height. +\* Here we use round robin. As Procs and Faulty are assigned non-deterministically, +\* it does not really matter who starts first. +Proposer(ht, rd) == PropFun[ht, rd] \*1 + ((ht + rd) % N) + +Id(v) == v + +IsValid(v) == v \in ValidValues + +\* here we start with StartRound(0) +Init == + /\ h = [p \in Procs |-> 0] + /\ round = [p \in Procs |-> 0] + /\ step = [p \in Procs |-> "PROPOSE"] + /\ decision = [p \in Procs |-> [ht \in Heights |-> nil]] + /\ lockedValue = [p \in Procs |-> nil] + /\ lockedRound = [p \in Procs |-> -1] + /\ validValue = [p \in Procs |-> nil] + /\ validRound = [p \in Procs |-> -1] + /\ \E v \in Values: + /\ msgsPropose = + [<> \in Heights \X Rounds |-> + IF ht = 0 /\ rd = 0 + THEN {[src |-> Proposer(0, 0), + proposal |-> v, validRound |-> -1]} \cup FaultyProposals + ELSE FaultyProposals \* only faulty messages + ] + /\ msgsPrevote = [<> \in Heights \X Rounds |-> FaultyPrevotes] + /\ msgsPrecommit = [<> \in Heights \X Rounds |-> FaultyPrecommits] + /\ oldEvents = {} <: {ET} + /\ timeoutPropose = { <> : p \in Procs \ {Proposer(0, 0)}} + /\ timeoutPrevote = {} <: {TimeoutT} \* no PREVOTE timeouts + /\ timeoutPrecommit = {} <: {TimeoutT} \* no PRECOMMIT timeouts + +\* lines 22-27 +UponProposalInPropose(p) == + \E v \in Values: + /\ step[p] = "PROPOSE" \* line 22 + /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> -1] + \in msgsPropose[h[p], round[p]] \* line 22 + /\ LET isGood == IsValid(v) /\ (lockedRound[p] = -1 \/ lockedValue[p] = v) IN \* line 23 + LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} + IN \* lines 24-26 + msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = + msgsPrevote[h[p], round[p]] \cup newMsgs] + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 28-33 +UponProposalInProposeAndPrevote(p) == + \E v \in Values, vr \in Rounds: + /\ step[p] = "PROPOSE" /\ 0 <= vr /\ vr < round[p] \* line 28, the while part + /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] + \in msgsPropose[h[p], round[p]] \* line 28 + /\ LET PV == { m \in msgsPrevote[h[p], vr]: m.hash = Id(v) } IN + AtLeastT2(PV) \* line 28 + /\ LET isGood == IsValid(v) /\ (lockedRound[p] <= vr \/ lockedValue[p] = v) IN \* line 29 + LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} + IN \* lines 30-32 + msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = + msgsPrevote[h[p], round[p]] \cup newMsgs] + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 34-35 +UponPrevoteFirstTime(p) == + /\ step[p] = "PREVOTE" \* line 34 + /\ AtLeastT2(msgsPrevote[h[p], round[p]]) \* line 34 + /\ LET event == [type |-> "PREVOTE", src |-> p, + h |-> h[p], round |-> round[p], value |-> nil] + IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* process it only once + /\ timeoutPrevote' = timeoutPrevote \cup {<>} \* line 35 + /\ UNCHANGED <> + +\* lines 36-46 +UponProposalInPrevoteOrCommitAndPrevote(p) == + \E v \in ValidValues, vr \in Rounds \cup {-1}: + /\ step[p] \in {"PREVOTE", "PRECOMMIT"} \* line 36 + /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] + \in msgsPropose[h[p], round[p]] \* line 36 + /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], + round |-> round[p], value |-> Id(v)] IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* record that it should not happen again + /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = Id(v) } IN + AtLeastT2(PV) \* line 36 + /\ lockedValue' = + IF step[p] = "PREVOTE" + THEN [lockedValue EXCEPT ![p] = v] \* line 38 + ELSE lockedValue \* else of line 37 + /\ lockedRound' = + IF step[p] = "PREVOTE" + THEN [lockedRound EXCEPT ![p] = round[p]] \* line 39 + ELSE lockedRound \* else of line 37 + /\ LET newMsgs == + IF step[p] = "PREVOTE" + THEN {[src |-> p, hash |-> Id(v)]} \* line 40 + ELSE {} <: {PrecommitT} + IN \* else of line 37 + msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = + msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 40, or else of 37 + /\ step' = + IF step[p] = "PREVOTE" + THEN [step EXCEPT ![p] = "PRECOMMIT"] + ELSE step \* line 41 + /\ validValue' = [validValue EXCEPT ![p] = v] \* line 42 + /\ validRound' = [validRound EXCEPT ![p] = round[p]] \* line 43 + /\ UNCHANGED <> + +\* Apparently, this action is needed to deal with a value proposed by a Byzantine process +\* lines 44-46 +UponPrevoteNil(p) == + /\ step[p] = "PREVOTE" \* line 44 + /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = nil } + IN + AtLeastT2(PV) \* line 34 + /\ step' = [step EXCEPT ![p] = "PRECOMMIT"] + /\ LET newMsgs == {[src |-> p, hash |-> nil]} \* line 45 + IN + msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = + msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 45 + /\ UNCHANGED <> + +\* lines 47-48 +UponPrecommitFirstTime(p) == + /\ AtLeastT2(msgsPrecommit[h[p], round[p]]) \* line 47 + /\ LET event == [type |-> "PRECOMMIT", src |-> p, + h |-> h[p], round |-> round[p], value |-> nil] + IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* process it only once + /\ timeoutPrecommit' = timeoutPrecommit \cup {<>} \* line 48 + /\ UNCHANGED <> + +\* lines 11-21 +StartRound(p, ht, r) == + /\ round' = [round EXCEPT ![p] = r] + /\ step' = [step EXCEPT ![p] = "PROPOSE"] + /\ \E v \in ValidValues: \* lines 14-21 + LET proposal == IF validValue[p] /= nil THEN validValue[p] ELSE v IN + LET newMsgs == + IF p = Proposer(ht, r) + THEN {[src |-> p, proposal |-> proposal, validRound |-> validRound[p]]} + ELSE {} <: {ProposalT} + IN + msgsPropose' = [msgsPropose EXCEPT ![ht, r] = + msgsPropose[ht, r] \cup newMsgs] \* line 19 + /\ LET newTimeouts == \* line 21 + IF p = Proposer(ht, r) + THEN {} <: {TimeoutT} \* no new timeouts + ELSE { <> } + IN + timeoutPropose' = timeoutPropose \cup newTimeouts + +\* lines 49-54 +UponProposalInPrecommitNoDecision(p) == + /\ h[p] + 1 \in Heights + \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING + /\ decision[p][h[p]] = nil \* line 49 + /\ \E v \in ValidValues (* line 50*) , r \in Rounds, vr \in Rounds \cup {-1}: + /\ [src |-> Proposer(h[p], r), proposal |-> v, validRound |-> vr] + \in msgsPropose[h[p], r] \* line 49 + /\ LET PV == { m \in msgsPrecommit[h[p], r]: m.hash = Id(v) } IN + AtLeastT2(PV) \* line 49 + /\ decision' = [decision EXCEPT ![p][h[p]] = v] \* update the decision, line 51 + /\ h' = [h EXCEPT ![p] = h[p] + 1] \* line 52 + \* line 53 + /\ lockedRound' = [lockedRound EXCEPT ![p] = -1] + /\ lockedValue' = [lockedValue EXCEPT ![p] = nil] + /\ validRound' = [validRound EXCEPT ![p] = -1] + /\ validValue' = [validValue EXCEPT ![p] = nil] + \* What does it mean to reset the message buffer? Do it for one process only? + /\ StartRound(p, h[p] + 1, 0) + /\ UNCHANGED <> + +\* lines 55-56 +UponCatchupRound(p) == + \E r \in Rounds: + /\ r > round[p] + /\ LET ps == { m.src : m \in msgsPropose[h[p], r]} IN + LET pv == { m.src : m \in msgsPrevote[h[p], r]} IN + LET pc == { m.src : m \in msgsPrecommit[h[p], r]} IN + AtLeastT1(ps \cup pv \cup pc) \* line 55 + /\ StartRound(p, h[p], r) + /\ UNCHANGED <> + +\* lines 57-60 +OnTimeoutPropose(p) == + \E tm \in timeoutPropose: \* a timeout occurs + /\ tm[1] = p + /\ timeoutPropose' = timeoutPropose \ {tm} \* remove from the future timeouts + /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PROPOSE" IN + /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PREVOTE"] ELSE step \* line 60 + /\ LET newMsgs == + IF UpdateNeeded + THEN {[src |-> tm[1], hash |-> nil]} \* line 59 + ELSE {} <: {PrevoteT} \* else of line 58 + IN \* line 59, or else of 58 + msgsPrevote' = [msgsPrevote EXCEPT ![tm[2], tm[3]] = + msgsPrevote[tm[2], tm[3]] \cup newMsgs] + /\ UNCHANGED <> + +\* lines 61-64 +OnTimeoutPrevote(p) == + \E tm \in timeoutPrevote: \* a timeout occurs + /\ tm[1] = p + /\ timeoutPrevote' = timeoutPrevote \ {tm} \* remove from the future timeouts + /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PREVOTE" IN + /\ step' = + IF UpdateNeeded + THEN [step EXCEPT ![p] = "PRECOMMIT"] + ELSE step \* line 64 + /\ LET newMsgs == + IF UpdateNeeded + THEN {[src |-> tm[1], hash |-> nil]} \* line 63 + ELSE {} <: {PrecommitT} \* else of line 62 + IN \* line 63, or else of 62 + msgsPrecommit' = [msgsPrecommit EXCEPT ![tm[2], tm[3]] = + msgsPrecommit[tm[2], tm[3]] \cup newMsgs] + /\ UNCHANGED <> + +\* lines 65-67 +OnTimeoutPrecommitOutside(p) == + \E tm \in timeoutPrecommit: \* a timeout occurs + /\ tm[1] = p + /\ (tm[2] /= h[p] \/ tm[3] /= round[p]) \* but we are in another round or height + /\ timeoutPrecommit' = timeoutPrecommit \ {tm} \* remove from the future timeouts + /\ UNCHANGED <> + +\* lines 65-67 +OnTimeoutPrecommitInside(p) == + /\ round[p] + 1 \in Rounds + \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING + /\ <> \in timeoutPrecommit \* the timeout occurs for the current round and height + /\ timeoutPrecommit' = timeoutPrecommit \ {<>} \* remove from the future timeouts + /\ StartRound(p, h[p], round[p] + 1) + /\ UNCHANGED <> + + +Next == + \/ \E p \in Procs: + \/ UponProposalInPropose(p) + \/ UponProposalInProposeAndPrevote(p) + \/ UponPrevoteFirstTime(p) + \/ UponProposalInPrevoteOrCommitAndPrevote(p) + \/ UponPrevoteNil(p) \* FIXME: disabled for model checking + \/ UponPrecommitFirstTime(p) + \/ UponProposalInPrecommitNoDecision(p) + \/ UponCatchupRound(p) + \/ OnTimeoutPropose(p) + \/ OnTimeoutPrevote(p) + \/ OnTimeoutPrecommitOutside(p) + \/ OnTimeoutPrecommitInside(p) + \* a safeguard to prevent deadlocks when the algorithm goes to further heights or rounds + \*\/ UNCHANGED vars + +\* safety +Agreement == + \A p, q \in Procs, ht \in Heights: + \/ decision[p][ht] = nil + \/ decision[q][ht] = nil + \/ decision[p][ht] = decision[q][ht] + +\* simple reachability properties to make sure that the algorithm is doing anything useful +NoDecision == \A p \in Procs, ht \in Heights: decision[p][ht] = nil + +NoPrecommit == \A p \in Procs: step[p] /= "PRECOMMIT" + +NoTwoLockedValues == + \A p, q \in Procs: + h[p] = h[q] => lockedValue[p] = nil \/ lockedValue[q] = nil \/ lockedValue[p] = lockedValue[q] + +NoTwoLockedRounds == + \A p, q \in Procs: + h[p] = h[q] => lockedRound[p] = -1 \/ lockedRound[q] = -1 \/ lockedRound[p] = lockedRound[q] + + +============================================================================= +\* Modification History +\* Last modified Fri Mar 22 08:57:10 CET 2019 by igor +\* Created Fri Mar 15 10:30:17 CET 2019 by igor diff --git a/docs/spec/tendermint-fork/Tendermint4n4f0.tla b/docs/spec/tendermint-fork/Tendermint4n4f0.tla new file mode 100644 index 000000000..fdd7169a7 --- /dev/null +++ b/docs/spec/tendermint-fork/Tendermint4n4f0.tla @@ -0,0 +1,387 @@ +----------------------------- MODULE Tendermint4n4f0 -------------------- +(* + A TLA+ specification of Tendermint consensus by Ethan Buchman, Jae Kwon, and Zarko Milosevic. + + For the moment, we assume the following: + + 1. Every process has the voting power of 1. + 2. Timeouts are non-deterministic (works for safety). + 3. The proposer function is non-deterministic (works for safety). + + Encoded in TLA+ by Igor Konnov. It took me 4 hours to translate the pseudo-code to TLA+. + + Version 3: assuming that f = 1, + using AtLeastT1(S) and AtLeastT2(s) instead of + Cardinality(S) >= f + 1 and Cardinality(S) >= 2f + 1 + *) + +EXTENDS Integers, FiniteSets + +CONSTANTS PropFun \* the proposer function + +N == 4 \* the total number of processes: correct and faulty +T == 0 \* an upper bound on the number of Byzantine processes +F == 0 \* the number of Byzantine processes +Procs == 1..N-F +Faulty == N-F+1..N +Heights == 0..1 \* the set of consensus instances +Rounds == 0..2 \* the set of possible rounds, give a bit more freedom to the solver +ValidValues == {0, 1} \* e.g., picked by a correct process, or a faulty one +InvalidValues == {2} \* e.g., sent by a Byzantine process +Values == ValidValues \cup InvalidValues \* all values +nil == -1 + +\* these are two tresholds that are used in the algorithm +THRESHOLD1 == T + 1 +THRESHOLD2 == 2 * T + 1 + +(* APALACHE-BEGIN annotations *) +a <: b == a + +MT == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, + proposal |-> Int, validRound |-> Int, hash |-> Int] +ProposalT == [src |-> Int, proposal |-> Int, validRound |-> Int] +PrevoteT == [src |-> Int, hash |-> Int] +PrecommitT == PrevoteT +ET == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, value |-> Int] \* processed events, "for the first time" + +\* this is an optimization, in order to avoid cardinality constraints +\* one faulty process: +\*AtLeastT1(S) == \E x, y \in S: x /= y +\*AtLeastT2(S) == \E x, y, z \in S: x /= y /\ x /= z /\ y /= z +\* no faults: +AtLeastT1(S) == \E x \in S: TRUE +AtLeastT2(S) == \E x, y \in S: x /= y + +ValueT == Int +RoundT == Int +TimeoutT == <> \* process, height, round +(* APALACHE-END *) + +FaultyProposals == + [src: Faulty, proposal: Values, validRound: Rounds \cup {-1}] + +FaultyPrevotes == [src: Faulty, hash: Values] + +FaultyPrecommits == [src: Faulty, hash: Values] + +ConstInit == PropFun \in [Heights \X Rounds -> Procs] + + +\* these variables are exactly as in the pseudo-code +VARIABLES h, round, step, decision, lockedValue, lockedRound, validValue, validRound + +\* book-keeping variables +VARIABLES msgsPropose, \* the propose messages broadcasted in the system, a function Heights \X Rounds -> set of messages + msgsPrevote, \* the prevote messages broadcasted in the system, a function Heights \X Rounds -> set of messages + msgsPrecommit, \* the precommit messages broadcasted in the system, a function Heights \X Rounds -> set of messages + oldEvents, \* the messages processed once, as expressed by "for the first time" + timeoutPropose, \* a set of proposed timeouts: <> + timeoutPrevote, \* a set of proposed timeouts: <> + timeoutPrecommit \* a set of proposed timeouts: <> + +\* this is needed for UNCHANGED +vars == <> + +\* A function which gives the proposer for a given round at a given height. +\* Here we use round robin. As Procs and Faulty are assigned non-deterministically, +\* it does not really matter who starts first. +Proposer(ht, rd) == PropFun[ht, rd] \*1 + ((ht + rd) % N) + +Id(v) == v + +IsValid(v) == v \in ValidValues + +\* here we start with StartRound(0) +Init == + /\ h = [p \in Procs |-> 0] + /\ round = [p \in Procs |-> 0] + /\ step = [p \in Procs |-> "PROPOSE"] + /\ decision = [p \in Procs |-> [ht \in Heights |-> nil]] + /\ lockedValue = [p \in Procs |-> nil] + /\ lockedRound = [p \in Procs |-> -1] + /\ validValue = [p \in Procs |-> nil] + /\ validRound = [p \in Procs |-> -1] + /\ \E v \in Values: + /\ msgsPropose = + [<> \in Heights \X Rounds |-> + IF ht = 0 /\ rd = 0 + THEN {[src |-> Proposer(0, 0), + proposal |-> v, validRound |-> -1]} \cup FaultyProposals + ELSE FaultyProposals \* only faulty messages + ] + /\ msgsPrevote = [<> \in Heights \X Rounds |-> FaultyPrevotes] + /\ msgsPrecommit = [<> \in Heights \X Rounds |-> FaultyPrecommits] + /\ oldEvents = {} <: {ET} + /\ timeoutPropose = { <> : p \in Procs \ {Proposer(0, 0)}} + /\ timeoutPrevote = {} <: {TimeoutT} \* no PREVOTE timeouts + /\ timeoutPrecommit = {} <: {TimeoutT} \* no PRECOMMIT timeouts + +\* lines 22-27 +UponProposalInPropose(p) == + \E v \in Values: + /\ step[p] = "PROPOSE" \* line 22 + /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> -1] + \in msgsPropose[h[p], round[p]] \* line 22 + /\ LET isGood == IsValid(v) /\ (lockedRound[p] = -1 \/ lockedValue[p] = v) IN \* line 23 + LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} + IN \* lines 24-26 + msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = + msgsPrevote[h[p], round[p]] \cup newMsgs] + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 28-33 +UponProposalInProposeAndPrevote(p) == + \E v \in Values, vr \in Rounds: + /\ step[p] = "PROPOSE" /\ 0 <= vr /\ vr < round[p] \* line 28, the while part + /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] + \in msgsPropose[h[p], round[p]] \* line 28 + /\ LET PV == { m \in msgsPrevote[h[p], vr]: m.hash = Id(v) } IN + AtLeastT2(PV) \* line 28 + /\ LET isGood == IsValid(v) /\ (lockedRound[p] <= vr \/ lockedValue[p] = v) IN \* line 29 + LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} + IN \* lines 30-32 + msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = + msgsPrevote[h[p], round[p]] \cup newMsgs] + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 34-35 +UponPrevoteFirstTime(p) == + /\ step[p] = "PREVOTE" \* line 34 + /\ AtLeastT2(msgsPrevote[h[p], round[p]]) \* line 34 + /\ LET event == [type |-> "PREVOTE", src |-> p, + h |-> h[p], round |-> round[p], value |-> nil] + IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* process it only once + /\ timeoutPrevote' = timeoutPrevote \cup {<>} \* line 35 + /\ UNCHANGED <> + +\* lines 36-46 +UponProposalInPrevoteOrCommitAndPrevote(p) == + \E v \in ValidValues, vr \in Rounds \cup {-1}: + /\ step[p] \in {"PREVOTE", "PRECOMMIT"} \* line 36 + /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] + \in msgsPropose[h[p], round[p]] \* line 36 + /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], + round |-> round[p], value |-> Id(v)] IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* record that it should not happen again + /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = Id(v) } IN + AtLeastT2(PV) \* line 36 + /\ lockedValue' = + IF step[p] = "PREVOTE" + THEN [lockedValue EXCEPT ![p] = v] \* line 38 + ELSE lockedValue \* else of line 37 + /\ lockedRound' = + IF step[p] = "PREVOTE" + THEN [lockedRound EXCEPT ![p] = round[p]] \* line 39 + ELSE lockedRound \* else of line 37 + /\ LET newMsgs == + IF step[p] = "PREVOTE" + THEN {[src |-> p, hash |-> Id(v)]} \* line 40 + ELSE {} <: {PrecommitT} + IN \* else of line 37 + msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = + msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 40, or else of 37 + /\ step' = + IF step[p] = "PREVOTE" + THEN [step EXCEPT ![p] = "PRECOMMIT"] + ELSE step \* line 41 + /\ validValue' = [validValue EXCEPT ![p] = v] \* line 42 + /\ validRound' = [validRound EXCEPT ![p] = round[p]] \* line 43 + /\ UNCHANGED <> + +\* Apparently, this action is needed to deal with a value proposed by a Byzantine process +\* lines 44-46 +UponPrevoteNil(p) == + /\ step[p] = "PREVOTE" \* line 44 + /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = nil } + IN + AtLeastT2(PV) \* line 34 + /\ step' = [step EXCEPT ![p] = "PRECOMMIT"] + /\ LET newMsgs == {[src |-> p, hash |-> nil]} \* line 45 + IN + msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = + msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 45 + /\ UNCHANGED <> + +\* lines 47-48 +UponPrecommitFirstTime(p) == + /\ AtLeastT2(msgsPrecommit[h[p], round[p]]) \* line 47 + /\ LET event == [type |-> "PRECOMMIT", src |-> p, + h |-> h[p], round |-> round[p], value |-> nil] + IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* process it only once + /\ timeoutPrecommit' = timeoutPrecommit \cup {<>} \* line 48 + /\ UNCHANGED <> + +\* lines 11-21 +StartRound(p, ht, r) == + /\ round' = [round EXCEPT ![p] = r] + /\ step' = [step EXCEPT ![p] = "PROPOSE"] + /\ \E v \in ValidValues: \* lines 14-21 + LET proposal == IF validValue[p] /= nil THEN validValue[p] ELSE v IN + LET newMsgs == + IF p = Proposer(ht, r) + THEN {[src |-> p, proposal |-> proposal, validRound |-> validRound[p]]} + ELSE {} <: {ProposalT} + IN + msgsPropose' = [msgsPropose EXCEPT ![ht, r] = + msgsPropose[ht, r] \cup newMsgs] \* line 19 + /\ LET newTimeouts == \* line 21 + IF p = Proposer(ht, r) + THEN {} <: {TimeoutT} \* no new timeouts + ELSE { <> } + IN + timeoutPropose' = timeoutPropose \cup newTimeouts + +\* lines 49-54 +UponProposalInPrecommitNoDecision(p) == + /\ h[p] + 1 \in Heights + \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING + /\ decision[p][h[p]] = nil \* line 49 + /\ \E v \in ValidValues (* line 50*) , r \in Rounds, vr \in Rounds \cup {-1}: + /\ [src |-> Proposer(h[p], r), proposal |-> v, validRound |-> vr] + \in msgsPropose[h[p], r] \* line 49 + /\ LET PV == { m \in msgsPrecommit[h[p], r]: m.hash = Id(v) } IN + AtLeastT2(PV) \* line 49 + /\ decision' = [decision EXCEPT ![p][h[p]] = v] \* update the decision, line 51 + /\ h' = [h EXCEPT ![p] = h[p] + 1] \* line 52 + \* line 53 + /\ lockedRound' = [lockedRound EXCEPT ![p] = -1] + /\ lockedValue' = [lockedValue EXCEPT ![p] = nil] + /\ validRound' = [validRound EXCEPT ![p] = -1] + /\ validValue' = [validValue EXCEPT ![p] = nil] + \* What does it mean to reset the message buffer? Do it for one process only? + /\ StartRound(p, h[p] + 1, 0) + /\ UNCHANGED <> + +\* lines 55-56 +UponCatchupRound(p) == + \E r \in Rounds: + /\ r > round[p] + /\ LET ps == { m.src : m \in msgsPropose[h[p], r]} IN + LET pv == { m.src : m \in msgsPrevote[h[p], r]} IN + LET pc == { m.src : m \in msgsPrecommit[h[p], r]} IN + AtLeastT1(ps \cup pv \cup pc) \* line 55 + /\ StartRound(p, h[p], r) + /\ UNCHANGED <> + +\* lines 57-60 +OnTimeoutPropose(p) == + \E tm \in timeoutPropose: \* a timeout occurs + /\ tm[1] = p + /\ timeoutPropose' = timeoutPropose \ {tm} \* remove from the future timeouts + /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PROPOSE" IN + /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PREVOTE"] ELSE step \* line 60 + /\ LET newMsgs == + IF UpdateNeeded + THEN {[src |-> tm[1], hash |-> nil]} \* line 59 + ELSE {} <: {PrevoteT} \* else of line 58 + IN \* line 59, or else of 58 + msgsPrevote' = [msgsPrevote EXCEPT ![tm[2], tm[3]] = + msgsPrevote[tm[2], tm[3]] \cup newMsgs] + /\ UNCHANGED <> + +\* lines 61-64 +OnTimeoutPrevote(p) == + \E tm \in timeoutPrevote: \* a timeout occurs + /\ tm[1] = p + /\ timeoutPrevote' = timeoutPrevote \ {tm} \* remove from the future timeouts + /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PREVOTE" IN + /\ step' = + IF UpdateNeeded + THEN [step EXCEPT ![p] = "PRECOMMIT"] + ELSE step \* line 64 + /\ LET newMsgs == + IF UpdateNeeded + THEN {[src |-> tm[1], hash |-> nil]} \* line 63 + ELSE {} <: {PrecommitT} \* else of line 62 + IN \* line 63, or else of 62 + msgsPrecommit' = [msgsPrecommit EXCEPT ![tm[2], tm[3]] = + msgsPrecommit[tm[2], tm[3]] \cup newMsgs] + /\ UNCHANGED <> + +\* lines 65-67 +OnTimeoutPrecommitOutside(p) == + \E tm \in timeoutPrecommit: \* a timeout occurs + /\ tm[1] = p + /\ (tm[2] /= h[p] \/ tm[3] /= round[p]) \* but we are in another round or height + /\ timeoutPrecommit' = timeoutPrecommit \ {tm} \* remove from the future timeouts + /\ UNCHANGED <> + +\* lines 65-67 +OnTimeoutPrecommitInside(p) == + /\ round[p] + 1 \in Rounds + \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING + /\ <> \in timeoutPrecommit \* the timeout occurs for the current round and height + /\ timeoutPrecommit' = timeoutPrecommit \ {<>} \* remove from the future timeouts + /\ StartRound(p, h[p], round[p] + 1) + /\ UNCHANGED <> + + +Next == + \/ \E p \in Procs: + \/ UponProposalInPropose(p) + \/ UponProposalInProposeAndPrevote(p) + \/ UponPrevoteFirstTime(p) + \/ UponProposalInPrevoteOrCommitAndPrevote(p) + \/ UponPrevoteNil(p) \* FIXME: disabled for model checking + \/ UponPrecommitFirstTime(p) + \/ UponProposalInPrecommitNoDecision(p) + \/ UponCatchupRound(p) + \/ OnTimeoutPropose(p) + \/ OnTimeoutPrevote(p) + \/ OnTimeoutPrecommitOutside(p) + \/ OnTimeoutPrecommitInside(p) + \* a safeguard to prevent deadlocks when the algorithm goes to further heights or rounds + \*\/ UNCHANGED vars + +\* safety +Agreement == + \A p, q \in Procs, ht \in Heights: + \/ decision[p][ht] = nil + \/ decision[q][ht] = nil + \/ decision[p][ht] = decision[q][ht] + +\* simple reachability properties to make sure that the algorithm is doing anything useful +NoDecision == \A p \in Procs, ht \in Heights: decision[p][ht] = nil + +NoPrecommit == \A p \in Procs: step[p] /= "PRECOMMIT" + +NoTwoLockedValues == + \A p, q \in Procs: + h[p] = h[q] => lockedValue[p] = nil \/ lockedValue[q] = nil \/ lockedValue[p] = lockedValue[q] + +NoTwoLockedRounds == + \A p, q \in Procs: + h[p] = h[q] => lockedRound[p] = -1 \/ lockedRound[q] = -1 \/ lockedRound[p] = lockedRound[q] + + +============================================================================= +\* Modification History +\* Last modified Fri Mar 22 08:57:10 CET 2019 by igor +\* Created Fri Mar 15 10:30:17 CET 2019 by igor diff --git a/docs/spec/tendermint-fork/Tendermint4n4f1.tla b/docs/spec/tendermint-fork/Tendermint4n4f1.tla new file mode 100644 index 000000000..cc8087ca7 --- /dev/null +++ b/docs/spec/tendermint-fork/Tendermint4n4f1.tla @@ -0,0 +1,392 @@ +----------------------------- MODULE Tendermint4n4f1 -------------------------- +(* + A TLA+ specification by Igor Konnov + of Tendermint consensus by Ethan Buchman, Jae Kwon, and Zarko Milosevic. + + For the moment, we assume the following: + + 1. Every process has the voting power of 1 (this seems to be complete). + 2. Timeouts are non-deterministic (works for safety). + 3. The proposer function is completely non-deterministic (works for safety). + + It took me 4 hours to translate the pseudo-code to TLA+. + Then it took me several days to make it more efficient for the model checker. + + Version 3: assuming that f = 1, + using AtLeastT1(S) and AtLeastT2(s) instead of + Cardinality(S) >= f + 1 and Cardinality(S) >= 2f + 1 + + Version 4: simplified record types, as we are using separate variables + for different message types and different indices for heights and rounds. + Injecting all Byzantine messages in the initial states. + *) + +EXTENDS Integers, FiniteSets + +CONSTANTS PropFun \* the proposer function + +N == 4 \* the total number of processes: correct and faulty +T == 1 \* an upper bound on the number of Byzantine processes +F == 1 \* the number of Byzantine processes +Procs == 1..N-F +Faulty == N-F+1..N +Heights == 0..1 \* the set of consensus instances +Rounds == 0..2 \* the set of possible rounds, give a bit more freedom to the solver +ValidValues == {0, 1} \* e.g., picked by a correct process, or a faulty one +InvalidValues == {2} \* e.g., sent by a Byzantine process +Values == ValidValues \cup InvalidValues \* all values +nil == -1 + +\* these are two tresholds that are used in the algorithm +THRESHOLD1 == T + 1 +THRESHOLD2 == 2 * T + 1 + +(* APALACHE-BEGIN annotations *) +a <: b == a + +MT == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, + proposal |-> Int, validRound |-> Int, hash |-> Int] +ProposalT == [src |-> Int, proposal |-> Int, validRound |-> Int] +PrevoteT == [src |-> Int, hash |-> Int] +PrecommitT == PrevoteT +ET == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, value |-> Int] \* processed events, "for the first time" + +\* This is an optimization, in order to avoid cardinality constraints +\* If T is different from 1, use the general operators: +\* AtLeastT1(S) == Cardinality(S) >= THRESHOLD1 +\* AtLeastT2(S) == Cardinality(S) >= THRESHOLD2 +AtLeastT1(S) == \E x, y \in S: x /= y +AtLeastT2(S) == \E x, y, z \in S: x /= y /\ x /= z /\ y /= z + +ValueT == Int +RoundT == Int +TimeoutT == <> \* process, height, round +(* APALACHE-END *) + +FaultyProposals == + [src: Faulty, proposal: Values, validRound: Rounds \cup {-1}] + +FaultyPrevotes == [src: Faulty, hash: Values] + +FaultyPrecommits == [src: Faulty, hash: Values] + +ConstInit == PropFun \in [Heights \X Rounds -> Procs] + + +\* these variables are exactly as in the pseudo-code +VARIABLES h, round, step, decision, lockedValue, lockedRound, validValue, validRound + +\* book-keeping variables +VARIABLES msgsPropose, \* the propose messages broadcasted in the system, a function Heights \X Rounds -> set of messages + msgsPrevote, \* the prevote messages broadcasted in the system, a function Heights \X Rounds -> set of messages + msgsPrecommit, \* the precommit messages broadcasted in the system, a function Heights \X Rounds -> set of messages + oldEvents, \* the messages processed once, as expressed by "for the first time" + timeoutPropose, \* a set of proposed timeouts: <> + timeoutPrevote, \* a set of proposed timeouts: <> + timeoutPrecommit \* a set of proposed timeouts: <> + +\* this is needed for UNCHANGED +vars == <> + +\* A function which gives the proposer for a given round at a given height. +\* Here we use round robin. As Procs and Faulty are assigned non-deterministically, +\* it does not really matter who starts first. +Proposer(ht, rd) == PropFun[ht, rd] \*1 + ((ht + rd) % N) + +Id(v) == v + +IsValid(v) == v \in ValidValues + +\* here we start with StartRound(0) +Init == + /\ h = [p \in Procs |-> 0] + /\ round = [p \in Procs |-> 0] + /\ step = [p \in Procs |-> "PROPOSE"] + /\ decision = [p \in Procs |-> [ht \in Heights |-> nil]] + /\ lockedValue = [p \in Procs |-> nil] + /\ lockedRound = [p \in Procs |-> -1] + /\ validValue = [p \in Procs |-> nil] + /\ validRound = [p \in Procs |-> -1] + /\ \E v \in Values: + /\ msgsPropose = + [<> \in Heights \X Rounds |-> + IF ht = 0 /\ rd = 0 + THEN {[src |-> Proposer(0, 0), + proposal |-> v, validRound |-> -1]} \cup FaultyProposals + ELSE FaultyProposals \* only faulty messages + ] + /\ msgsPrevote = [<> \in Heights \X Rounds |-> FaultyPrevotes] + /\ msgsPrecommit = [<> \in Heights \X Rounds |-> FaultyPrecommits] + /\ oldEvents = {} <: {ET} + /\ timeoutPropose = { <> : p \in Procs \ {Proposer(0, 0)}} + /\ timeoutPrevote = {} <: {TimeoutT} \* no PREVOTE timeouts + /\ timeoutPrecommit = {} <: {TimeoutT} \* no PRECOMMIT timeouts + +\* lines 22-27 +UponProposalInPropose(p) == + \E v \in Values: + /\ step[p] = "PROPOSE" \* line 22 + /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> -1] + \in msgsPropose[h[p], round[p]] \* line 22 + /\ LET isGood == IsValid(v) /\ (lockedRound[p] = -1 \/ lockedValue[p] = v) IN \* line 23 + LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} + IN \* lines 24-26 + msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = + msgsPrevote[h[p], round[p]] \cup newMsgs] + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 28-33 +UponProposalInProposeAndPrevote(p) == + \E v \in Values, vr \in Rounds: + /\ step[p] = "PROPOSE" /\ 0 <= vr /\ vr < round[p] \* line 28, the while part + /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] + \in msgsPropose[h[p], round[p]] \* line 28 + /\ LET PV == { m \in msgsPrevote[h[p], vr]: m.hash = Id(v) } IN + AtLeastT2(PV) \* line 28 + /\ LET isGood == IsValid(v) /\ (lockedRound[p] <= vr \/ lockedValue[p] = v) IN \* line 29 + LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} + IN \* lines 30-32 + msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = + msgsPrevote[h[p], round[p]] \cup newMsgs] + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 34-35 +UponPrevoteFirstTime(p) == + /\ step[p] = "PREVOTE" \* line 34 + /\ AtLeastT2(msgsPrevote[h[p], round[p]]) \* line 34 + /\ LET event == [type |-> "PREVOTE", src |-> p, + h |-> h[p], round |-> round[p], value |-> nil] + IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* process it only once + /\ timeoutPrevote' = timeoutPrevote \cup {<>} \* line 35 + /\ UNCHANGED <> + +\* lines 36-46 +UponProposalInPrevoteOrCommitAndPrevote(p) == + \E v \in ValidValues, vr \in Rounds \cup {-1}: + /\ step[p] \in {"PREVOTE", "PRECOMMIT"} \* line 36 + /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] + \in msgsPropose[h[p], round[p]] \* line 36 + /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], + round |-> round[p], value |-> Id(v)] IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* record that it should not happen again + /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = Id(v) } IN + AtLeastT2(PV) \* line 36 + /\ lockedValue' = + IF step[p] = "PREVOTE" + THEN [lockedValue EXCEPT ![p] = v] \* line 38 + ELSE lockedValue \* else of line 37 + /\ lockedRound' = + IF step[p] = "PREVOTE" + THEN [lockedRound EXCEPT ![p] = round[p]] \* line 39 + ELSE lockedRound \* else of line 37 + /\ LET newMsgs == + IF step[p] = "PREVOTE" + THEN {[src |-> p, hash |-> Id(v)]} \* line 40 + ELSE {} <: {PrecommitT} + IN \* else of line 37 + msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = + msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 40, or else of 37 + /\ step' = + IF step[p] = "PREVOTE" + THEN [step EXCEPT ![p] = "PRECOMMIT"] + ELSE step \* line 41 + /\ validValue' = [validValue EXCEPT ![p] = v] \* line 42 + /\ validRound' = [validRound EXCEPT ![p] = round[p]] \* line 43 + /\ UNCHANGED <> + +\* Apparently, this action is needed to deal with a value proposed by a Byzantine process +\* lines 44-46 +UponPrevoteNil(p) == + /\ step[p] = "PREVOTE" \* line 44 + /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = nil } + IN + AtLeastT2(PV) \* line 34 + /\ step' = [step EXCEPT ![p] = "PRECOMMIT"] + /\ LET newMsgs == {[src |-> p, hash |-> nil]} \* line 45 + IN + msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = + msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 45 + /\ UNCHANGED <> + +\* lines 47-48 +UponPrecommitFirstTime(p) == + /\ AtLeastT2(msgsPrecommit[h[p], round[p]]) \* line 47 + /\ LET event == [type |-> "PRECOMMIT", src |-> p, + h |-> h[p], round |-> round[p], value |-> nil] + IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* process it only once + /\ timeoutPrecommit' = timeoutPrecommit \cup {<>} \* line 48 + /\ UNCHANGED <> + +\* lines 11-21 +StartRound(p, ht, r) == + /\ round' = [round EXCEPT ![p] = r] + /\ step' = [step EXCEPT ![p] = "PROPOSE"] + /\ \E v \in ValidValues: \* lines 14-21 + LET proposal == IF validValue[p] /= nil THEN validValue[p] ELSE v IN + LET newMsgs == + IF p = Proposer(ht, r) + THEN {[src |-> p, proposal |-> proposal, validRound |-> validRound[p]]} + ELSE {} <: {ProposalT} + IN + msgsPropose' = [msgsPropose EXCEPT ![ht, r] = + msgsPropose[ht, r] \cup newMsgs] \* line 19 + /\ LET newTimeouts == \* line 21 + IF p = Proposer(ht, r) + THEN {} <: {TimeoutT} \* no new timeouts + ELSE { <> } + IN + timeoutPropose' = timeoutPropose \cup newTimeouts + +\* lines 49-54 +UponProposalInPrecommitNoDecision(p) == + /\ h[p] + 1 \in Heights + \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING + /\ decision[p][h[p]] = nil \* line 49 + /\ \E v \in ValidValues (* line 50*) , r \in Rounds, vr \in Rounds \cup {-1}: + /\ [src |-> Proposer(h[p], r), proposal |-> v, validRound |-> vr] + \in msgsPropose[h[p], r] \* line 49 + /\ LET PV == { m \in msgsPrecommit[h[p], r]: m.hash = Id(v) } IN + AtLeastT2(PV) \* line 49 + /\ decision' = [decision EXCEPT ![p][h[p]] = v] \* update the decision, line 51 + /\ h' = [h EXCEPT ![p] = h[p] + 1] \* line 52 + \* line 53 + /\ lockedRound' = [lockedRound EXCEPT ![p] = -1] + /\ lockedValue' = [lockedValue EXCEPT ![p] = nil] + /\ validRound' = [validRound EXCEPT ![p] = -1] + /\ validValue' = [validValue EXCEPT ![p] = nil] + \* What does it mean to reset the message buffer? Do it for one process only? + /\ StartRound(p, h[p] + 1, 0) + /\ UNCHANGED <> + +\* lines 55-56 +UponCatchupRound(p) == + \E r \in Rounds: + /\ r > round[p] + /\ LET ps == { m.src : m \in msgsPropose[h[p], r]} IN + LET pv == { m.src : m \in msgsPrevote[h[p], r]} IN + LET pc == { m.src : m \in msgsPrecommit[h[p], r]} IN + AtLeastT1(ps \cup pv \cup pc) \* line 55 + /\ StartRound(p, h[p], r) + /\ UNCHANGED <> + +\* lines 57-60 +OnTimeoutPropose(p) == + \E tm \in timeoutPropose: \* a timeout occurs + /\ tm[1] = p + /\ timeoutPropose' = timeoutPropose \ {tm} \* remove from the future timeouts + /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PROPOSE" IN + /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PREVOTE"] ELSE step \* line 60 + /\ LET newMsgs == + IF UpdateNeeded + THEN {[src |-> tm[1], hash |-> nil]} \* line 59 + ELSE {} <: {PrevoteT} \* else of line 58 + IN \* line 59, or else of 58 + msgsPrevote' = [msgsPrevote EXCEPT ![tm[2], tm[3]] = + msgsPrevote[tm[2], tm[3]] \cup newMsgs] + /\ UNCHANGED <> + +\* lines 61-64 +OnTimeoutPrevote(p) == + \E tm \in timeoutPrevote: \* a timeout occurs + /\ tm[1] = p + /\ timeoutPrevote' = timeoutPrevote \ {tm} \* remove from the future timeouts + /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PREVOTE" IN + /\ step' = + IF UpdateNeeded + THEN [step EXCEPT ![p] = "PRECOMMIT"] + ELSE step \* line 64 + /\ LET newMsgs == + IF UpdateNeeded + THEN {[src |-> tm[1], hash |-> nil]} \* line 63 + ELSE {} <: {PrecommitT} \* else of line 62 + IN \* line 63, or else of 62 + msgsPrecommit' = [msgsPrecommit EXCEPT ![tm[2], tm[3]] = + msgsPrecommit[tm[2], tm[3]] \cup newMsgs] + /\ UNCHANGED <> + +\* lines 65-67 +OnTimeoutPrecommitOutside(p) == + \E tm \in timeoutPrecommit: \* a timeout occurs + /\ tm[1] = p + /\ (tm[2] /= h[p] \/ tm[3] /= round[p]) \* but we are in another round or height + /\ timeoutPrecommit' = timeoutPrecommit \ {tm} \* remove from the future timeouts + /\ UNCHANGED <> + +\* lines 65-67 +OnTimeoutPrecommitInside(p) == + /\ round[p] + 1 \in Rounds + \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING + /\ <> \in timeoutPrecommit \* the timeout occurs for the current round and height + /\ timeoutPrecommit' = timeoutPrecommit \ {<>} \* remove from the future timeouts + /\ StartRound(p, h[p], round[p] + 1) + /\ UNCHANGED <> + + +Next == + \/ \E p \in Procs: + \/ UponProposalInPropose(p) + \/ UponProposalInProposeAndPrevote(p) + \/ UponPrevoteFirstTime(p) + \/ UponProposalInPrevoteOrCommitAndPrevote(p) + \/ UponPrevoteNil(p) \* FIXME: disabled for model checking + \/ UponPrecommitFirstTime(p) + \/ UponProposalInPrecommitNoDecision(p) + \/ UponCatchupRound(p) + \/ OnTimeoutPropose(p) + \/ OnTimeoutPrevote(p) + \/ OnTimeoutPrecommitOutside(p) + \/ OnTimeoutPrecommitInside(p) + \* a safeguard to prevent deadlocks when the algorithm goes to further heights or rounds + \*\/ UNCHANGED vars + +\* safety +Agreement == + \A p, q \in Procs, ht \in Heights: + \/ decision[p][ht] = nil + \/ decision[q][ht] = nil + \/ decision[p][ht] = decision[q][ht] + +\* simple reachability properties to make sure that the algorithm is doing anything useful +NoDecision == \A p \in Procs, ht \in Heights: decision[p][ht] = nil + +NoPrecommit == \A p \in Procs: step[p] /= "PRECOMMIT" + +NoTwoLockedValues == + \A p, q \in Procs: + h[p] = h[q] => lockedValue[p] = nil \/ lockedValue[q] = nil \/ lockedValue[p] = lockedValue[q] + +NoTwoLockedRounds == + \A p, q \in Procs: + h[p] = h[q] => lockedRound[p] = -1 \/ lockedRound[q] = -1 \/ lockedRound[p] = lockedRound[q] + + +============================================================================= +\* Modification History +\* Last modified Fri Mar 22 08:57:10 CET 2019 by igor +\* Created Fri Mar 15 10:30:17 CET 2019 by igor diff --git a/docs/spec/tendermint-fork/Tendermint4n4f2.tla b/docs/spec/tendermint-fork/Tendermint4n4f2.tla new file mode 100644 index 000000000..57c3e130c --- /dev/null +++ b/docs/spec/tendermint-fork/Tendermint4n4f2.tla @@ -0,0 +1,392 @@ +----------------------------- MODULE Tendermint4n4f2 -------------------------- +(* + A TLA+ specification by Igor Konnov + of Tendermint consensus by Ethan Buchman, Jae Kwon, and Zarko Milosevic. + + For the moment, we assume the following: + + 1. Every process has the voting power of 1 (this seems to be complete). + 2. Timeouts are non-deterministic (works for safety). + 3. The proposer function is completely non-deterministic (works for safety). + + It took me 4 hours to translate the pseudo-code to TLA+. + Then it took me several days to make it more efficient for the model checker. + + Version 3: assuming that f = 1, + using AtLeastT1(S) and AtLeastT2(s) instead of + Cardinality(S) >= f + 1 and Cardinality(S) >= 2f + 1 + + Version 4: simplified record types, as we are using separate variables + for different message types and different indices for heights and rounds. + Injecting all Byzantine messages in the initial states. + *) + +EXTENDS Integers, FiniteSets + +CONSTANTS PropFun \* the proposer function + +N == 4 \* the total number of processes: correct and faulty +T == 1 \* an upper bound on the number of Byzantine processes +F == 2 \* the number of Byzantine processes +Procs == 1..N-F +Faulty == N-F+1..N +Heights == 0..1 \* the set of consensus instances +Rounds == 0..2 \* the set of possible rounds, give a bit more freedom to the solver +ValidValues == {0, 1} \* e.g., picked by a correct process, or a faulty one +InvalidValues == {2} \* e.g., sent by a Byzantine process +Values == ValidValues \cup InvalidValues \* all values +nil == -1 + +\* these are two tresholds that are used in the algorithm +THRESHOLD1 == T + 1 +THRESHOLD2 == 2 * T + 1 + +(* APALACHE-BEGIN annotations *) +a <: b == a + +MT == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, + proposal |-> Int, validRound |-> Int, hash |-> Int] +ProposalT == [src |-> Int, proposal |-> Int, validRound |-> Int] +PrevoteT == [src |-> Int, hash |-> Int] +PrecommitT == PrevoteT +ET == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, value |-> Int] \* processed events, "for the first time" + +\* This is an optimization, in order to avoid cardinality constraints +\* If T is different from 1, use the general operators: +\* AtLeastT1(S) == Cardinality(S) >= THRESHOLD1 +\* AtLeastT2(S) == Cardinality(S) >= THRESHOLD2 +AtLeastT1(S) == \E x, y \in S: x /= y +AtLeastT2(S) == \E x, y, z \in S: x /= y /\ x /= z /\ y /= z + +ValueT == Int +RoundT == Int +TimeoutT == <> \* process, height, round +(* APALACHE-END *) + +FaultyProposals == + [src: Faulty, proposal: Values, validRound: Rounds \cup {-1}] + +FaultyPrevotes == [src: Faulty, hash: Values] + +FaultyPrecommits == [src: Faulty, hash: Values] + +ConstInit == PropFun \in [Heights \X Rounds -> Procs] + + +\* these variables are exactly as in the pseudo-code +VARIABLES h, round, step, decision, lockedValue, lockedRound, validValue, validRound + +\* book-keeping variables +VARIABLES msgsPropose, \* the propose messages broadcasted in the system, a function Heights \X Rounds -> set of messages + msgsPrevote, \* the prevote messages broadcasted in the system, a function Heights \X Rounds -> set of messages + msgsPrecommit, \* the precommit messages broadcasted in the system, a function Heights \X Rounds -> set of messages + oldEvents, \* the messages processed once, as expressed by "for the first time" + timeoutPropose, \* a set of proposed timeouts: <> + timeoutPrevote, \* a set of proposed timeouts: <> + timeoutPrecommit \* a set of proposed timeouts: <> + +\* this is needed for UNCHANGED +vars == <> + +\* A function which gives the proposer for a given round at a given height. +\* Here we use round robin. As Procs and Faulty are assigned non-deterministically, +\* it does not really matter who starts first. +Proposer(ht, rd) == PropFun[ht, rd] \*1 + ((ht + rd) % N) + +Id(v) == v + +IsValid(v) == v \in ValidValues + +\* here we start with StartRound(0) +Init == + /\ h = [p \in Procs |-> 0] + /\ round = [p \in Procs |-> 0] + /\ step = [p \in Procs |-> "PROPOSE"] + /\ decision = [p \in Procs |-> [ht \in Heights |-> nil]] + /\ lockedValue = [p \in Procs |-> nil] + /\ lockedRound = [p \in Procs |-> -1] + /\ validValue = [p \in Procs |-> nil] + /\ validRound = [p \in Procs |-> -1] + /\ \E v \in Values: + /\ msgsPropose = + [<> \in Heights \X Rounds |-> + IF ht = 0 /\ rd = 0 + THEN {[src |-> Proposer(0, 0), + proposal |-> v, validRound |-> -1]} \cup FaultyProposals + ELSE FaultyProposals \* only faulty messages + ] + /\ msgsPrevote = [<> \in Heights \X Rounds |-> FaultyPrevotes] + /\ msgsPrecommit = [<> \in Heights \X Rounds |-> FaultyPrecommits] + /\ oldEvents = {} <: {ET} + /\ timeoutPropose = { <> : p \in Procs \ {Proposer(0, 0)}} + /\ timeoutPrevote = {} <: {TimeoutT} \* no PREVOTE timeouts + /\ timeoutPrecommit = {} <: {TimeoutT} \* no PRECOMMIT timeouts + +\* lines 22-27 +UponProposalInPropose(p) == + \E v \in Values: + /\ step[p] = "PROPOSE" \* line 22 + /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> -1] + \in msgsPropose[h[p], round[p]] \* line 22 + /\ LET isGood == IsValid(v) /\ (lockedRound[p] = -1 \/ lockedValue[p] = v) IN \* line 23 + LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} + IN \* lines 24-26 + msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = + msgsPrevote[h[p], round[p]] \cup newMsgs] + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 28-33 +UponProposalInProposeAndPrevote(p) == + \E v \in Values, vr \in Rounds: + /\ step[p] = "PROPOSE" /\ 0 <= vr /\ vr < round[p] \* line 28, the while part + /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] + \in msgsPropose[h[p], round[p]] \* line 28 + /\ LET PV == { m \in msgsPrevote[h[p], vr]: m.hash = Id(v) } IN + AtLeastT2(PV) \* line 28 + /\ LET isGood == IsValid(v) /\ (lockedRound[p] <= vr \/ lockedValue[p] = v) IN \* line 29 + LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} + IN \* lines 30-32 + msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = + msgsPrevote[h[p], round[p]] \cup newMsgs] + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 34-35 +UponPrevoteFirstTime(p) == + /\ step[p] = "PREVOTE" \* line 34 + /\ AtLeastT2(msgsPrevote[h[p], round[p]]) \* line 34 + /\ LET event == [type |-> "PREVOTE", src |-> p, + h |-> h[p], round |-> round[p], value |-> nil] + IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* process it only once + /\ timeoutPrevote' = timeoutPrevote \cup {<>} \* line 35 + /\ UNCHANGED <> + +\* lines 36-46 +UponProposalInPrevoteOrCommitAndPrevote(p) == + \E v \in ValidValues, vr \in Rounds \cup {-1}: + /\ step[p] \in {"PREVOTE", "PRECOMMIT"} \* line 36 + /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] + \in msgsPropose[h[p], round[p]] \* line 36 + /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], + round |-> round[p], value |-> Id(v)] IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* record that it should not happen again + /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = Id(v) } IN + AtLeastT2(PV) \* line 36 + /\ lockedValue' = + IF step[p] = "PREVOTE" + THEN [lockedValue EXCEPT ![p] = v] \* line 38 + ELSE lockedValue \* else of line 37 + /\ lockedRound' = + IF step[p] = "PREVOTE" + THEN [lockedRound EXCEPT ![p] = round[p]] \* line 39 + ELSE lockedRound \* else of line 37 + /\ LET newMsgs == + IF step[p] = "PREVOTE" + THEN {[src |-> p, hash |-> Id(v)]} \* line 40 + ELSE {} <: {PrecommitT} + IN \* else of line 37 + msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = + msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 40, or else of 37 + /\ step' = + IF step[p] = "PREVOTE" + THEN [step EXCEPT ![p] = "PRECOMMIT"] + ELSE step \* line 41 + /\ validValue' = [validValue EXCEPT ![p] = v] \* line 42 + /\ validRound' = [validRound EXCEPT ![p] = round[p]] \* line 43 + /\ UNCHANGED <> + +\* Apparently, this action is needed to deal with a value proposed by a Byzantine process +\* lines 44-46 +UponPrevoteNil(p) == + /\ step[p] = "PREVOTE" \* line 44 + /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = nil } + IN + AtLeastT2(PV) \* line 34 + /\ step' = [step EXCEPT ![p] = "PRECOMMIT"] + /\ LET newMsgs == {[src |-> p, hash |-> nil]} \* line 45 + IN + msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = + msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 45 + /\ UNCHANGED <> + +\* lines 47-48 +UponPrecommitFirstTime(p) == + /\ AtLeastT2(msgsPrecommit[h[p], round[p]]) \* line 47 + /\ LET event == [type |-> "PRECOMMIT", src |-> p, + h |-> h[p], round |-> round[p], value |-> nil] + IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* process it only once + /\ timeoutPrecommit' = timeoutPrecommit \cup {<>} \* line 48 + /\ UNCHANGED <> + +\* lines 11-21 +StartRound(p, ht, r) == + /\ round' = [round EXCEPT ![p] = r] + /\ step' = [step EXCEPT ![p] = "PROPOSE"] + /\ \E v \in ValidValues: \* lines 14-21 + LET proposal == IF validValue[p] /= nil THEN validValue[p] ELSE v IN + LET newMsgs == + IF p = Proposer(ht, r) + THEN {[src |-> p, proposal |-> proposal, validRound |-> validRound[p]]} + ELSE {} <: {ProposalT} + IN + msgsPropose' = [msgsPropose EXCEPT ![ht, r] = + msgsPropose[ht, r] \cup newMsgs] \* line 19 + /\ LET newTimeouts == \* line 21 + IF p = Proposer(ht, r) + THEN {} <: {TimeoutT} \* no new timeouts + ELSE { <> } + IN + timeoutPropose' = timeoutPropose \cup newTimeouts + +\* lines 49-54 +UponProposalInPrecommitNoDecision(p) == + /\ h[p] + 1 \in Heights + \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING + /\ decision[p][h[p]] = nil \* line 49 + /\ \E v \in ValidValues (* line 50*) , r \in Rounds, vr \in Rounds \cup {-1}: + /\ [src |-> Proposer(h[p], r), proposal |-> v, validRound |-> vr] + \in msgsPropose[h[p], r] \* line 49 + /\ LET PV == { m \in msgsPrecommit[h[p], r]: m.hash = Id(v) } IN + AtLeastT2(PV) \* line 49 + /\ decision' = [decision EXCEPT ![p][h[p]] = v] \* update the decision, line 51 + /\ h' = [h EXCEPT ![p] = h[p] + 1] \* line 52 + \* line 53 + /\ lockedRound' = [lockedRound EXCEPT ![p] = -1] + /\ lockedValue' = [lockedValue EXCEPT ![p] = nil] + /\ validRound' = [validRound EXCEPT ![p] = -1] + /\ validValue' = [validValue EXCEPT ![p] = nil] + \* What does it mean to reset the message buffer? Do it for one process only? + /\ StartRound(p, h[p] + 1, 0) + /\ UNCHANGED <> + +\* lines 55-56 +UponCatchupRound(p) == + \E r \in Rounds: + /\ r > round[p] + /\ LET ps == { m.src : m \in msgsPropose[h[p], r]} IN + LET pv == { m.src : m \in msgsPrevote[h[p], r]} IN + LET pc == { m.src : m \in msgsPrecommit[h[p], r]} IN + AtLeastT1(ps \cup pv \cup pc) \* line 55 + /\ StartRound(p, h[p], r) + /\ UNCHANGED <> + +\* lines 57-60 +OnTimeoutPropose(p) == + \E tm \in timeoutPropose: \* a timeout occurs + /\ tm[1] = p + /\ timeoutPropose' = timeoutPropose \ {tm} \* remove from the future timeouts + /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PROPOSE" IN + /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PREVOTE"] ELSE step \* line 60 + /\ LET newMsgs == + IF UpdateNeeded + THEN {[src |-> tm[1], hash |-> nil]} \* line 59 + ELSE {} <: {PrevoteT} \* else of line 58 + IN \* line 59, or else of 58 + msgsPrevote' = [msgsPrevote EXCEPT ![tm[2], tm[3]] = + msgsPrevote[tm[2], tm[3]] \cup newMsgs] + /\ UNCHANGED <> + +\* lines 61-64 +OnTimeoutPrevote(p) == + \E tm \in timeoutPrevote: \* a timeout occurs + /\ tm[1] = p + /\ timeoutPrevote' = timeoutPrevote \ {tm} \* remove from the future timeouts + /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PREVOTE" IN + /\ step' = + IF UpdateNeeded + THEN [step EXCEPT ![p] = "PRECOMMIT"] + ELSE step \* line 64 + /\ LET newMsgs == + IF UpdateNeeded + THEN {[src |-> tm[1], hash |-> nil]} \* line 63 + ELSE {} <: {PrecommitT} \* else of line 62 + IN \* line 63, or else of 62 + msgsPrecommit' = [msgsPrecommit EXCEPT ![tm[2], tm[3]] = + msgsPrecommit[tm[2], tm[3]] \cup newMsgs] + /\ UNCHANGED <> + +\* lines 65-67 +OnTimeoutPrecommitOutside(p) == + \E tm \in timeoutPrecommit: \* a timeout occurs + /\ tm[1] = p + /\ (tm[2] /= h[p] \/ tm[3] /= round[p]) \* but we are in another round or height + /\ timeoutPrecommit' = timeoutPrecommit \ {tm} \* remove from the future timeouts + /\ UNCHANGED <> + +\* lines 65-67 +OnTimeoutPrecommitInside(p) == + /\ round[p] + 1 \in Rounds + \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING + /\ <> \in timeoutPrecommit \* the timeout occurs for the current round and height + /\ timeoutPrecommit' = timeoutPrecommit \ {<>} \* remove from the future timeouts + /\ StartRound(p, h[p], round[p] + 1) + /\ UNCHANGED <> + + +Next == + \/ \E p \in Procs: + \/ UponProposalInPropose(p) + \/ UponProposalInProposeAndPrevote(p) + \/ UponPrevoteFirstTime(p) + \/ UponProposalInPrevoteOrCommitAndPrevote(p) + \/ UponPrevoteNil(p) \* FIXME: disabled for model checking + \/ UponPrecommitFirstTime(p) + \/ UponProposalInPrecommitNoDecision(p) + \/ UponCatchupRound(p) + \/ OnTimeoutPropose(p) + \/ OnTimeoutPrevote(p) + \/ OnTimeoutPrecommitOutside(p) + \/ OnTimeoutPrecommitInside(p) + \* a safeguard to prevent deadlocks when the algorithm goes to further heights or rounds + \*\/ UNCHANGED vars + +\* safety +Agreement == + \A p, q \in Procs, ht \in Heights: + \/ decision[p][ht] = nil + \/ decision[q][ht] = nil + \/ decision[p][ht] = decision[q][ht] + +\* simple reachability properties to make sure that the algorithm is doing anything useful +NoDecision == \A p \in Procs, ht \in Heights: decision[p][ht] = nil + +NoPrecommit == \A p \in Procs: step[p] /= "PRECOMMIT" + +NoTwoLockedValues == + \A p, q \in Procs: + h[p] = h[q] => lockedValue[p] = nil \/ lockedValue[q] = nil \/ lockedValue[p] = lockedValue[q] + +NoTwoLockedRounds == + \A p, q \in Procs: + h[p] = h[q] => lockedRound[p] = -1 \/ lockedRound[q] = -1 \/ lockedRound[p] = lockedRound[q] + + +============================================================================= +\* Modification History +\* Last modified Fri Mar 22 08:57:10 CET 2019 by igor +\* Created Fri Mar 15 10:30:17 CET 2019 by igor diff --git a/docs/spec/tendermint-fork/Tendermint4n5f1T3.tla b/docs/spec/tendermint-fork/Tendermint4n5f1T3.tla new file mode 100644 index 000000000..829494d0a --- /dev/null +++ b/docs/spec/tendermint-fork/Tendermint4n5f1T3.tla @@ -0,0 +1,393 @@ +---------------------- MODULE Tendermint4n5f1T3 ----------------------------- +(* + A TLA+ specification by Igor Konnov + of Tendermint consensus by Ethan Buchman, Jae Kwon, and Zarko Milosevic. + + For the moment, we assume the following: + + 1. Every process has the voting power of 1 (this seems to be complete). + 2. Timeouts are non-deterministic (works for safety). + 3. The proposer function is completely non-deterministic (works for safety). + + It took me 4 hours to translate the pseudo-code to TLA+. + Then it took me several days to make it more efficient for the model checker. + + Version 3: assuming that f = 1, + using AtLeastT1(S) and AtLeastT2(s) instead of + Cardinality(S) >= f + 1 and Cardinality(S) >= 2f + 1 + + Version 4: simplified record types, as we are using separate variables + for different message types and different indices for heights and rounds. + Injecting all Byzantine messages in the initial states. + *) + +EXTENDS Integers, FiniteSets + +CONSTANTS PropFun \* the proposer function + +N == 5 \* the total number of processes: correct and faulty +T == 1 \* an upper bound on the number of Byzantine processes +F == 1 \* the number of Byzantine processes +Procs == 1..N-F +Faulty == N-F+1..N +Heights == 0..1 \* the set of consensus instances +Rounds == 0..2 \* the set of possible rounds, give a bit more freedom to the solver +ValidValues == {0, 1} \* e.g., picked by a correct process, or a faulty one +InvalidValues == {2} \* e.g., sent by a Byzantine process +Values == ValidValues \cup InvalidValues \* all values +nil == -1 + +\* these are two tresholds that are used in the algorithm +THRESHOLD1 == T + 1 +THRESHOLD2 == N - T + +(* APALACHE-BEGIN annotations *) +a <: b == a + +MT == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, + proposal |-> Int, validRound |-> Int, hash |-> Int] +ProposalT == [src |-> Int, proposal |-> Int, validRound |-> Int] +PrevoteT == [src |-> Int, hash |-> Int] +PrecommitT == PrevoteT +ET == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, value |-> Int] \* processed events, "for the first time" + +\* This is an optimization, in order to avoid cardinality constraints +\* If T is different from 1, use the general operators: +\*AtLeastT1(S) == Cardinality(S) >= THRESHOLD1 +\*AtLeastT2(S) == Cardinality(S) >= THRESHOLD2 +AtLeastT1(S) == \E x, y \in S: x /= y +AtLeastT2(S) == \E w, x, y, z \in S: + x /= y /\ x /= z /\ y /= z /\ w /= x /\ w /= y /\ w /= z + +ValueT == Int +RoundT == Int +TimeoutT == <> \* process, height, round +(* APALACHE-END *) + +FaultyProposals == + [src: Faulty, proposal: Values, validRound: Rounds \cup {-1}] + +FaultyPrevotes == [src: Faulty, hash: Values] + +FaultyPrecommits == [src: Faulty, hash: Values] + +ConstInit == PropFun \in [Heights \X Rounds -> Procs] + + +\* these variables are exactly as in the pseudo-code +VARIABLES h, round, step, decision, lockedValue, lockedRound, validValue, validRound + +\* book-keeping variables +VARIABLES msgsPropose, \* the propose messages broadcasted in the system, a function Heights \X Rounds -> set of messages + msgsPrevote, \* the prevote messages broadcasted in the system, a function Heights \X Rounds -> set of messages + msgsPrecommit, \* the precommit messages broadcasted in the system, a function Heights \X Rounds -> set of messages + oldEvents, \* the messages processed once, as expressed by "for the first time" + timeoutPropose, \* a set of proposed timeouts: <> + timeoutPrevote, \* a set of proposed timeouts: <> + timeoutPrecommit \* a set of proposed timeouts: <> + +\* this is needed for UNCHANGED +vars == <> + +\* A function which gives the proposer for a given round at a given height. +\* Here we use round robin. As Procs and Faulty are assigned non-deterministically, +\* it does not really matter who starts first. +Proposer(ht, rd) == PropFun[ht, rd] \*1 + ((ht + rd) % N) + +Id(v) == v + +IsValid(v) == v \in ValidValues + +\* here we start with StartRound(0) +Init == + /\ h = [p \in Procs |-> 0] + /\ round = [p \in Procs |-> 0] + /\ step = [p \in Procs |-> "PROPOSE"] + /\ decision = [p \in Procs |-> [ht \in Heights |-> nil]] + /\ lockedValue = [p \in Procs |-> nil] + /\ lockedRound = [p \in Procs |-> -1] + /\ validValue = [p \in Procs |-> nil] + /\ validRound = [p \in Procs |-> -1] + /\ \E v \in Values: + /\ msgsPropose = + [<> \in Heights \X Rounds |-> + IF ht = 0 /\ rd = 0 + THEN {[src |-> Proposer(0, 0), + proposal |-> v, validRound |-> -1]} \cup FaultyProposals + ELSE FaultyProposals \* only faulty messages + ] + /\ msgsPrevote = [<> \in Heights \X Rounds |-> FaultyPrevotes] + /\ msgsPrecommit = [<> \in Heights \X Rounds |-> FaultyPrecommits] + /\ oldEvents = {} <: {ET} + /\ timeoutPropose = { <> : p \in Procs \ {Proposer(0, 0)}} + /\ timeoutPrevote = {} <: {TimeoutT} \* no PREVOTE timeouts + /\ timeoutPrecommit = {} <: {TimeoutT} \* no PRECOMMIT timeouts + +\* lines 22-27 +UponProposalInPropose(p) == + \E v \in Values: + /\ step[p] = "PROPOSE" \* line 22 + /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> -1] + \in msgsPropose[h[p], round[p]] \* line 22 + /\ LET isGood == IsValid(v) /\ (lockedRound[p] = -1 \/ lockedValue[p] = v) IN \* line 23 + LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} + IN \* lines 24-26 + msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = + msgsPrevote[h[p], round[p]] \cup newMsgs] + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 28-33 +UponProposalInProposeAndPrevote(p) == + \E v \in Values, vr \in Rounds: + /\ step[p] = "PROPOSE" /\ 0 <= vr /\ vr < round[p] \* line 28, the while part + /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] + \in msgsPropose[h[p], round[p]] \* line 28 + /\ LET PV == { m \in msgsPrevote[h[p], vr]: m.hash = Id(v) } IN + AtLeastT2(PV) \* line 28 + /\ LET isGood == IsValid(v) /\ (lockedRound[p] <= vr \/ lockedValue[p] = v) IN \* line 29 + LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} + IN \* lines 30-32 + msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = + msgsPrevote[h[p], round[p]] \cup newMsgs] + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 34-35 +UponPrevoteFirstTime(p) == + /\ step[p] = "PREVOTE" \* line 34 + /\ AtLeastT2(msgsPrevote[h[p], round[p]]) \* line 34 + /\ LET event == [type |-> "PREVOTE", src |-> p, + h |-> h[p], round |-> round[p], value |-> nil] + IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* process it only once + /\ timeoutPrevote' = timeoutPrevote \cup {<>} \* line 35 + /\ UNCHANGED <> + +\* lines 36-46 +UponProposalInPrevoteOrCommitAndPrevote(p) == + \E v \in ValidValues, vr \in Rounds \cup {-1}: + /\ step[p] \in {"PREVOTE", "PRECOMMIT"} \* line 36 + /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] + \in msgsPropose[h[p], round[p]] \* line 36 + /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], + round |-> round[p], value |-> Id(v)] IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* record that it should not happen again + /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = Id(v) } IN + AtLeastT2(PV) \* line 36 + /\ lockedValue' = + IF step[p] = "PREVOTE" + THEN [lockedValue EXCEPT ![p] = v] \* line 38 + ELSE lockedValue \* else of line 37 + /\ lockedRound' = + IF step[p] = "PREVOTE" + THEN [lockedRound EXCEPT ![p] = round[p]] \* line 39 + ELSE lockedRound \* else of line 37 + /\ LET newMsgs == + IF step[p] = "PREVOTE" + THEN {[src |-> p, hash |-> Id(v)]} \* line 40 + ELSE {} <: {PrecommitT} + IN \* else of line 37 + msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = + msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 40, or else of 37 + /\ step' = + IF step[p] = "PREVOTE" + THEN [step EXCEPT ![p] = "PRECOMMIT"] + ELSE step \* line 41 + /\ validValue' = [validValue EXCEPT ![p] = v] \* line 42 + /\ validRound' = [validRound EXCEPT ![p] = round[p]] \* line 43 + /\ UNCHANGED <> + +\* Apparently, this action is needed to deal with a value proposed by a Byzantine process +\* lines 44-46 +UponPrevoteNil(p) == + /\ step[p] = "PREVOTE" \* line 44 + /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = nil } + IN + AtLeastT2(PV) \* line 34 + /\ step' = [step EXCEPT ![p] = "PRECOMMIT"] + /\ LET newMsgs == {[src |-> p, hash |-> nil]} \* line 45 + IN + msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = + msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 45 + /\ UNCHANGED <> + +\* lines 47-48 +UponPrecommitFirstTime(p) == + /\ AtLeastT2(msgsPrecommit[h[p], round[p]]) \* line 47 + /\ LET event == [type |-> "PRECOMMIT", src |-> p, + h |-> h[p], round |-> round[p], value |-> nil] + IN + /\ event \notin oldEvents \* for the first time + /\ oldEvents' = oldEvents \cup {event} \* process it only once + /\ timeoutPrecommit' = timeoutPrecommit \cup {<>} \* line 48 + /\ UNCHANGED <> + +\* lines 11-21 +StartRound(p, ht, r) == + /\ round' = [round EXCEPT ![p] = r] + /\ step' = [step EXCEPT ![p] = "PROPOSE"] + /\ \E v \in ValidValues: \* lines 14-21 + LET proposal == IF validValue[p] /= nil THEN validValue[p] ELSE v IN + LET newMsgs == + IF p = Proposer(ht, r) + THEN {[src |-> p, proposal |-> proposal, validRound |-> validRound[p]]} + ELSE {} <: {ProposalT} + IN + msgsPropose' = [msgsPropose EXCEPT ![ht, r] = + msgsPropose[ht, r] \cup newMsgs] \* line 19 + /\ LET newTimeouts == \* line 21 + IF p = Proposer(ht, r) + THEN {} <: {TimeoutT} \* no new timeouts + ELSE { <> } + IN + timeoutPropose' = timeoutPropose \cup newTimeouts + +\* lines 49-54 +UponProposalInPrecommitNoDecision(p) == + /\ h[p] + 1 \in Heights + \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING + /\ decision[p][h[p]] = nil \* line 49 + /\ \E v \in ValidValues (* line 50*) , r \in Rounds, vr \in Rounds \cup {-1}: + /\ [src |-> Proposer(h[p], r), proposal |-> v, validRound |-> vr] + \in msgsPropose[h[p], r] \* line 49 + /\ LET PV == { m \in msgsPrecommit[h[p], r]: m.hash = Id(v) } IN + AtLeastT2(PV) \* line 49 + /\ decision' = [decision EXCEPT ![p][h[p]] = v] \* update the decision, line 51 + /\ h' = [h EXCEPT ![p] = h[p] + 1] \* line 52 + \* line 53 + /\ lockedRound' = [lockedRound EXCEPT ![p] = -1] + /\ lockedValue' = [lockedValue EXCEPT ![p] = nil] + /\ validRound' = [validRound EXCEPT ![p] = -1] + /\ validValue' = [validValue EXCEPT ![p] = nil] + \* What does it mean to reset the message buffer? Do it for one process only? + /\ StartRound(p, h[p] + 1, 0) + /\ UNCHANGED <> + +\* lines 55-56 +UponCatchupRound(p) == + \E r \in Rounds: + /\ r > round[p] + /\ LET ps == { m.src : m \in msgsPropose[h[p], r]} IN + LET pv == { m.src : m \in msgsPrevote[h[p], r]} IN + LET pc == { m.src : m \in msgsPrecommit[h[p], r]} IN + AtLeastT1(ps \cup pv \cup pc) \* line 55 + /\ StartRound(p, h[p], r) + /\ UNCHANGED <> + +\* lines 57-60 +OnTimeoutPropose(p) == + \E tm \in timeoutPropose: \* a timeout occurs + /\ tm[1] = p + /\ timeoutPropose' = timeoutPropose \ {tm} \* remove from the future timeouts + /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PROPOSE" IN + /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PREVOTE"] ELSE step \* line 60 + /\ LET newMsgs == + IF UpdateNeeded + THEN {[src |-> tm[1], hash |-> nil]} \* line 59 + ELSE {} <: {PrevoteT} \* else of line 58 + IN \* line 59, or else of 58 + msgsPrevote' = [msgsPrevote EXCEPT ![tm[2], tm[3]] = + msgsPrevote[tm[2], tm[3]] \cup newMsgs] + /\ UNCHANGED <> + +\* lines 61-64 +OnTimeoutPrevote(p) == + \E tm \in timeoutPrevote: \* a timeout occurs + /\ tm[1] = p + /\ timeoutPrevote' = timeoutPrevote \ {tm} \* remove from the future timeouts + /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PREVOTE" IN + /\ step' = + IF UpdateNeeded + THEN [step EXCEPT ![p] = "PRECOMMIT"] + ELSE step \* line 64 + /\ LET newMsgs == + IF UpdateNeeded + THEN {[src |-> tm[1], hash |-> nil]} \* line 63 + ELSE {} <: {PrecommitT} \* else of line 62 + IN \* line 63, or else of 62 + msgsPrecommit' = [msgsPrecommit EXCEPT ![tm[2], tm[3]] = + msgsPrecommit[tm[2], tm[3]] \cup newMsgs] + /\ UNCHANGED <> + +\* lines 65-67 +OnTimeoutPrecommitOutside(p) == + \E tm \in timeoutPrecommit: \* a timeout occurs + /\ tm[1] = p + /\ (tm[2] /= h[p] \/ tm[3] /= round[p]) \* but we are in another round or height + /\ timeoutPrecommit' = timeoutPrecommit \ {tm} \* remove from the future timeouts + /\ UNCHANGED <> + +\* lines 65-67 +OnTimeoutPrecommitInside(p) == + /\ round[p] + 1 \in Rounds + \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING + /\ <> \in timeoutPrecommit \* the timeout occurs for the current round and height + /\ timeoutPrecommit' = timeoutPrecommit \ {<>} \* remove from the future timeouts + /\ StartRound(p, h[p], round[p] + 1) + /\ UNCHANGED <> + + +Next == + \/ \E p \in Procs: + \/ UponProposalInPropose(p) + \/ UponProposalInProposeAndPrevote(p) + \/ UponPrevoteFirstTime(p) + \/ UponProposalInPrevoteOrCommitAndPrevote(p) + \/ UponPrevoteNil(p) \* FIXME: disabled for model checking + \/ UponPrecommitFirstTime(p) + \/ UponProposalInPrecommitNoDecision(p) + \/ UponCatchupRound(p) + \/ OnTimeoutPropose(p) + \/ OnTimeoutPrevote(p) + \/ OnTimeoutPrecommitOutside(p) + \/ OnTimeoutPrecommitInside(p) + \* a safeguard to prevent deadlocks when the algorithm goes to further heights or rounds + \*\/ UNCHANGED vars + +\* safety +Agreement == + \A p, q \in Procs, ht \in Heights: + \/ decision[p][ht] = nil + \/ decision[q][ht] = nil + \/ decision[p][ht] = decision[q][ht] + +\* simple reachability properties to make sure that the algorithm is doing anything useful +NoDecision == \A p \in Procs, ht \in Heights: decision[p][ht] = nil + +NoPrecommit == \A p \in Procs: step[p] /= "PRECOMMIT" + +NoTwoLockedValues == + \A p, q \in Procs: + h[p] = h[q] => lockedValue[p] = nil \/ lockedValue[q] = nil \/ lockedValue[p] = lockedValue[q] + +NoTwoLockedRounds == + \A p, q \in Procs: + h[p] = h[q] => lockedRound[p] = -1 \/ lockedRound[q] = -1 \/ lockedRound[p] = lockedRound[q] + + +============================================================================= +\* Modification History +\* Last modified Fri Mar 22 08:57:10 CET 2019 by igor +\* Created Fri Mar 15 10:30:17 CET 2019 by igor diff --git a/docs/spec/tendermint-fork/apalache-n4f1.properties b/docs/spec/tendermint-fork/apalache-n4f1.properties new file mode 100644 index 000000000..c534db654 --- /dev/null +++ b/docs/spec/tendermint-fork/apalache-n4f1.properties @@ -0,0 +1,7 @@ +search.transitionFilter=0,11,9,0 +#search.invariantFilter=5|6 +#search.invariantFilter=1[5-9] +search.transition.timeout=7200 +search.invariant.timeout=7200 +#search.invariantFilter=[7-9]|1[0-7] +#search.learnFromUnsat=true diff --git a/docs/spec/tendermint-fork/apalache-n4f2.properties b/docs/spec/tendermint-fork/apalache-n4f2.properties new file mode 100644 index 000000000..abde56385 --- /dev/null +++ b/docs/spec/tendermint-fork/apalache-n4f2.properties @@ -0,0 +1,7 @@ +#search.transitionFilter=0,11,9,0 +#search.invariantFilter=5|6 +#search.invariantFilter=1[5-9] +search.transition.timeout=7200 +search.invariant.timeout=7200 +#search.invariantFilter=[7-9]|1[0-7] +#search.learnFromUnsat=true diff --git a/docs/spec/tendermint-fork/apalache-n5f1.properties b/docs/spec/tendermint-fork/apalache-n5f1.properties new file mode 100644 index 000000000..596ae892e --- /dev/null +++ b/docs/spec/tendermint-fork/apalache-n5f1.properties @@ -0,0 +1,10 @@ +x = [^02]|[1-2][0-9] +search.transitionFilter=0,11,11,9,9,0,${x},${x},${x},${x},${x},${x},${x} +#search.transitionFilter=0,11,11,9,9,0,${x},${x},${x},${x},${x},${x},${x} +#search.invariantFilter=5|6 +search.invariantFilter=1[3-9] +#search.invariantFilter=1[3-9] +search.transition.timeout=7200 +#search.invariant.timeout=7200 +#search.invariantFilter=[7-9]|1[0-7] +#search.learnFromUnsat=true diff --git a/docs/spec/tendermint-fork/apalache-n5f1T3.properties b/docs/spec/tendermint-fork/apalache-n5f1T3.properties new file mode 100644 index 000000000..fd0dbef36 --- /dev/null +++ b/docs/spec/tendermint-fork/apalache-n5f1T3.properties @@ -0,0 +1,9 @@ +x = [^02]|[1-2][0-9] +search.transitionFilter=0,11,11,11,9,9,9,0,${x},${x},${x},${x},${x},${x},${x},${x},${x} +search.invariantFilter=1[7-9] +#search.transitionFilter=0,11,11,9,9,0,${x},${x},${x},${x},${x},${x},${x},${x} +#search.invariantFilter=5|6 +search.transition.timeout=7200 +#search.invariant.timeout=7200 +#search.invariantFilter=[7-9]|1[0-7] +#search.learnFromUnsat=true diff --git a/docs/spec/tendermint-fork/apalache.properties b/docs/spec/tendermint-fork/apalache.properties new file mode 100644 index 000000000..83d945372 --- /dev/null +++ b/docs/spec/tendermint-fork/apalache.properties @@ -0,0 +1,7 @@ +search.transitionFilter=0,11,11,9,9,0,0 +#search.invariantFilter=5|6 +#search.invariantFilter=1[5-9] +search.transition.timeout=7200 +search.invariant.timeout=7200 +#search.invariantFilter=[7-9]|1[0-7] +#search.learnFromUnsat=true From f5794fa6959ac9cab2d5609842f3098370a73997 Mon Sep 17 00:00:00 2001 From: Igor Konnov Date: Thu, 30 Jul 2020 15:32:27 +0200 Subject: [PATCH 2/6] moved the PR from verification --- .../001indinv-apalache.csv | 31 + .../001indinv-apalache.ini | 8 + docs/spec/tendermint-fork-cases/MC_n10_f3.tla | 26 + docs/spec/tendermint-fork-cases/MC_n10_f4.tla | 26 + docs/spec/tendermint-fork-cases/MC_n4_f1.tla | 26 + docs/spec/tendermint-fork-cases/MC_n4_f2.tla | 26 + docs/spec/tendermint-fork-cases/MC_n4_f3.tla | 26 + docs/spec/tendermint-fork-cases/MC_n5_f1.tla | 26 + docs/spec/tendermint-fork-cases/MC_n5_f2.tla | 26 + docs/spec/tendermint-fork-cases/MC_n7_f2.tla | 26 + docs/spec/tendermint-fork-cases/MC_n7_f3.tla | 26 + docs/spec/tendermint-fork-cases/MC_n7_f4.tla | 26 + docs/spec/tendermint-fork-cases/README.md | 105 + .../tendermint-fork-cases/TendermintAcc3.tla | 447 ++ .../TendermintAccDebug3.tla | 100 + .../TendermintAccInv3.tla | 323 ++ .../tendermint-fork-cases/apalache.properties | 11 + .../counterexample-vc0-w1.tla | 4009 +++++++++++++++++ .../counterexample-vc0-w2.tla | 3576 +++++++++++++++ .../counterexample-vc0-w3.tla | 3023 +++++++++++++ .../counterexample-vc31-w1.tla | 651 +++ .../tendermint-fork-cases/counterexample.tla | 3028 +++++++++++++ docs/spec/tendermint-fork-cases/run.sh | 9 + docs/spec/tendermint-fork/Tendermint.tla | 374 -- docs/spec/tendermint-fork/Tendermint3.tla | 376 -- docs/spec/tendermint-fork/Tendermint4.tla | 392 -- docs/spec/tendermint-fork/Tendermint4n4f0.tla | 387 -- docs/spec/tendermint-fork/Tendermint4n4f1.tla | 392 -- docs/spec/tendermint-fork/Tendermint4n4f2.tla | 392 -- .../tendermint-fork/Tendermint4n5f1T3.tla | 393 -- .../tendermint-fork/apalache-n4f1.properties | 7 - .../tendermint-fork/apalache-n4f2.properties | 7 - .../tendermint-fork/apalache-n5f1.properties | 10 - .../apalache-n5f1T3.properties | 9 - docs/spec/tendermint-fork/apalache.properties | 7 - 35 files changed, 15581 insertions(+), 2746 deletions(-) create mode 100644 docs/spec/tendermint-fork-cases/001indinv-apalache.csv create mode 100644 docs/spec/tendermint-fork-cases/001indinv-apalache.ini create mode 100644 docs/spec/tendermint-fork-cases/MC_n10_f3.tla create mode 100644 docs/spec/tendermint-fork-cases/MC_n10_f4.tla create mode 100644 docs/spec/tendermint-fork-cases/MC_n4_f1.tla create mode 100644 docs/spec/tendermint-fork-cases/MC_n4_f2.tla create mode 100644 docs/spec/tendermint-fork-cases/MC_n4_f3.tla create mode 100644 docs/spec/tendermint-fork-cases/MC_n5_f1.tla create mode 100644 docs/spec/tendermint-fork-cases/MC_n5_f2.tla create mode 100644 docs/spec/tendermint-fork-cases/MC_n7_f2.tla create mode 100644 docs/spec/tendermint-fork-cases/MC_n7_f3.tla create mode 100644 docs/spec/tendermint-fork-cases/MC_n7_f4.tla create mode 100644 docs/spec/tendermint-fork-cases/README.md create mode 100644 docs/spec/tendermint-fork-cases/TendermintAcc3.tla create mode 100644 docs/spec/tendermint-fork-cases/TendermintAccDebug3.tla create mode 100644 docs/spec/tendermint-fork-cases/TendermintAccInv3.tla create mode 100644 docs/spec/tendermint-fork-cases/apalache.properties create mode 100644 docs/spec/tendermint-fork-cases/counterexample-vc0-w1.tla create mode 100644 docs/spec/tendermint-fork-cases/counterexample-vc0-w2.tla create mode 100644 docs/spec/tendermint-fork-cases/counterexample-vc0-w3.tla create mode 100644 docs/spec/tendermint-fork-cases/counterexample-vc31-w1.tla create mode 100644 docs/spec/tendermint-fork-cases/counterexample.tla create mode 100755 docs/spec/tendermint-fork-cases/run.sh delete mode 100644 docs/spec/tendermint-fork/Tendermint.tla delete mode 100644 docs/spec/tendermint-fork/Tendermint3.tla delete mode 100644 docs/spec/tendermint-fork/Tendermint4.tla delete mode 100644 docs/spec/tendermint-fork/Tendermint4n4f0.tla delete mode 100644 docs/spec/tendermint-fork/Tendermint4n4f1.tla delete mode 100644 docs/spec/tendermint-fork/Tendermint4n4f2.tla delete mode 100644 docs/spec/tendermint-fork/Tendermint4n5f1T3.tla delete mode 100644 docs/spec/tendermint-fork/apalache-n4f1.properties delete mode 100644 docs/spec/tendermint-fork/apalache-n4f2.properties delete mode 100644 docs/spec/tendermint-fork/apalache-n5f1.properties delete mode 100644 docs/spec/tendermint-fork/apalache-n5f1T3.properties delete mode 100644 docs/spec/tendermint-fork/apalache.properties diff --git a/docs/spec/tendermint-fork-cases/001indinv-apalache.csv b/docs/spec/tendermint-fork-cases/001indinv-apalache.csv new file mode 100644 index 000000000..39c3d1865 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/001indinv-apalache.csv @@ -0,0 +1,31 @@ +no,filename,tool,timeout,init,inv,next,args +1,MC_n4_f1.tla,apalache,10h,TypedInv,TypedInv,,--length=1 --cinit=ConstInit +2,MC_n4_f2.tla,apalache,10h,TypedInv,TypedInv,,--length=1 --cinit=ConstInit +3,MC_n4_f3.tla,apalache,10h,TypedInv,TypedInv,,--length=1 --cinit=ConstInit +4,MC_n5_f1.tla,apalache,10h,TypedInv,TypedInv,,--length=1 --cinit=ConstInit +5,MC_n5_f2.tla,apalache,10h,TypedInv,TypedInv,,--length=1 --cinit=ConstInit +6,MC_n7_f2.tla,apalache,10h,TypedInv,TypedInv,,--length=1 --cinit=ConstInit +7,MC_n7_f3.tla,apalache,10h,TypedInv,TypedInv,,--length=1 --cinit=ConstInit +8,MC_n7_f4.tla,apalache,10h,TypedInv,TypedInv,,--length=1 --cinit=ConstInit +9,MC_n10_f3.tla,apalache,24h,TypedInv,TypedInv,,--length=1 --cinit=ConstInit +10,MC_n10_f4.tla,apalache,24h,TypedInv,TypedInv,,--length=1 --cinit=ConstInit +11,MC_n4_f1.tla,apalache,10h,TypedInv,Agreement,,--length=0 --cinit=ConstInit +12,MC_n4_f2.tla,apalache,10h,TypedInv,AgreementOrEquivocationOrAmnesia,,--length=0 --cinit=ConstInit +13,MC_n4_f3.tla,apalache,10h,TypedInv,AgreementOrEquivocationOrAmnesia,,--length=0 --cinit=ConstInit +14,MC_n5_f1.tla,apalache,10h,TypedInv,Agreement,,--length=0 --cinit=ConstInit +15,MC_n5_f2.tla,apalache,10h,TypedInv,AgreementOrEquivocationOrAmnesia,,--length=0 --cinit=ConstInit +16,MC_n7_f2.tla,apalache,10h,TypedInv,Agreement,,--length=0 --cinit=ConstInit +17,MC_n7_f3.tla,apalache,10h,TypedInv,AgreementOrEquivocationOrAmnesia,,--length=0 --cinit=ConstInit +18,MC_n7_f4.tla,apalache,10h,TypedInv,AgreementOrEquivocationOrAmnesia,,--length=0 --cinit=ConstInit +19,MC_n10_f3.tla,apalache,24h,TypedInv,Agreement,,--length=0 --cinit=ConstInit +20,MC_n10_f4.tla,apalache,24h,TypedInv,AgreementOrEquivocationOrAmnesia,,--length=0 --cinit=ConstInit +21,MC_n4_f1.tla,apalache,10h,Init,TypedInv,,--length=0 --cinit=ConstInit +22,MC_n4_f2.tla,apalache,10h,Init,TypedInv,,--length=0 --cinit=ConstInit +23,MC_n4_f3.tla,apalache,10h,Init,TypedInv,,--length=0 --cinit=ConstInit +24,MC_n5_f1.tla,apalache,10h,Init,TypedInv,,--length=0 --cinit=ConstInit +25,MC_n5_f2.tla,apalache,10h,Init,TypedInv,,--length=0 --cinit=ConstInit +26,MC_n7_f2.tla,apalache,10h,Init,TypedInv,,--length=0 --cinit=ConstInit +27,MC_n7_f3.tla,apalache,10h,Init,TypedInv,,--length=0 --cinit=ConstInit +28,MC_n7_f4.tla,apalache,10h,Init,TypedInv,,--length=0 --cinit=ConstInit +29,MC_n10_f3.tla,apalache,24h,Init,TypedInv,,--length=0 --cinit=ConstInit +30,MC_n10_f4.tla,apalache,24h,Init,TypedInv,,--length=0 --cinit=ConstInit diff --git a/docs/spec/tendermint-fork-cases/001indinv-apalache.ini b/docs/spec/tendermint-fork-cases/001indinv-apalache.ini new file mode 100644 index 000000000..da6c3a30c --- /dev/null +++ b/docs/spec/tendermint-fork-cases/001indinv-apalache.ini @@ -0,0 +1,8 @@ +# a configuration file for apalache-tests/scripts/mk-run.py + +[apalache-unstable] +more_args= + +[apalache-card] +more_args= + diff --git a/docs/spec/tendermint-fork-cases/MC_n10_f3.tla b/docs/spec/tendermint-fork-cases/MC_n10_f3.tla new file mode 100644 index 000000000..0f20f92b5 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/MC_n10_f3.tla @@ -0,0 +1,26 @@ +----------------------------- MODULE MC_n10_f3 ------------------------------- +CONSTANT Proposer \* the proposer function from 0..NRounds to 1..N + +\* the variables declared in TendermintAcc3 +VARIABLES + round, step, decision, lockedValue, lockedRound, validValue, validRound, + msgsPropose, msgsPrevote, msgsPrecommit, evidence + +\* an operator for type annotations +a <: b == a + +INSTANCE TendermintAccDebug3 WITH + Corr <- {"c1", "c2", "c3", "c4", "c5", "c6", "c7"}, + Defective <- {} <: {STRING}, + Byzantine <- {"f8", "f9", "f10"}, + N <- 10, + T <- 3, + ValidValues <- { "v0", "v1" }, + InvalidValues <- {"v2"}, + MaxRound <- 2 + +\* run Apalache with --cinit=ConstInit +ConstInit == \* the proposer is arbitrary -- works for safety + Proposer \in [Rounds -> AllProcs] + +============================================================================= diff --git a/docs/spec/tendermint-fork-cases/MC_n10_f4.tla b/docs/spec/tendermint-fork-cases/MC_n10_f4.tla new file mode 100644 index 000000000..3271dcd4c --- /dev/null +++ b/docs/spec/tendermint-fork-cases/MC_n10_f4.tla @@ -0,0 +1,26 @@ +----------------------------- MODULE MC_n10_f4 ------------------------------- +CONSTANT Proposer \* the proposer function from 0..NRounds to 1..N + +\* the variables declared in TendermintAcc3 +VARIABLES + round, step, decision, lockedValue, lockedRound, validValue, validRound, + msgsPropose, msgsPrevote, msgsPrecommit, evidence + +\* an operator for type annotations +a <: b == a + +INSTANCE TendermintAccDebug3 WITH + Corr <- {"c1", "c2", "c3", "c4", "c5", "c6"}, + Defective <- {"f7"}, + Byzantine <- {"f8", "f9", "f10"}, + N <- 10, + T <- 3, + ValidValues <- { "v0", "v1" }, + InvalidValues <- {"v2"}, + MaxRound <- 2 + +\* run Apalache with --cinit=ConstInit +ConstInit == \* the proposer is arbitrary -- works for safety + Proposer \in [Rounds -> AllProcs] + +============================================================================= diff --git a/docs/spec/tendermint-fork-cases/MC_n4_f1.tla b/docs/spec/tendermint-fork-cases/MC_n4_f1.tla new file mode 100644 index 000000000..94a9558d3 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/MC_n4_f1.tla @@ -0,0 +1,26 @@ +----------------------------- MODULE MC_n4_f1 ------------------------------- +CONSTANT Proposer \* the proposer function from 0..NRounds to 1..N + +\* the variables declared in TendermintAcc3 +VARIABLES + round, step, decision, lockedValue, lockedRound, validValue, validRound, + msgsPropose, msgsPrevote, msgsPrecommit, evidence + +\* an operator for type annotations +a <: b == a + +INSTANCE TendermintAccDebug3 WITH + Corr <- {"c1", "c2", "c3"}, + Defective <- {} <: {STRING}, + Byzantine <- {"f1"}, + N <- 4, + T <- 1, + ValidValues <- { "v0", "v1" }, + InvalidValues <- {"v2"}, + MaxRound <- 2 + +\* run Apalache with --cinit=ConstInit +ConstInit == \* the proposer is arbitrary -- works for safety + Proposer \in [Rounds -> AllProcs] + +============================================================================= diff --git a/docs/spec/tendermint-fork-cases/MC_n4_f2.tla b/docs/spec/tendermint-fork-cases/MC_n4_f2.tla new file mode 100644 index 000000000..91eae547f --- /dev/null +++ b/docs/spec/tendermint-fork-cases/MC_n4_f2.tla @@ -0,0 +1,26 @@ +----------------------------- MODULE MC_n4_f2 ------------------------------- +CONSTANT Proposer \* the proposer function from 0..NRounds to 1..N + +\* the variables declared in TendermintAcc3 +VARIABLES + round, step, decision, lockedValue, lockedRound, validValue, validRound, + msgsPropose, msgsPrevote, msgsPrecommit, evidence + +\* an operator for type annotations +a <: b == a + +INSTANCE TendermintAccDebug3 WITH + Corr <- {"c1", "c2"}, + Defective <- {"f3"}, + Byzantine <- {"f4"}, + N <- 4, + T <- 1, + ValidValues <- { "v0", "v1" }, + InvalidValues <- {"v2"}, + MaxRound <- 2 + +\* run Apalache with --cinit=ConstInit +ConstInit == \* the proposer is arbitrary -- works for safety + Proposer \in [Rounds -> AllProcs] + +============================================================================= diff --git a/docs/spec/tendermint-fork-cases/MC_n4_f3.tla b/docs/spec/tendermint-fork-cases/MC_n4_f3.tla new file mode 100644 index 000000000..4413817b5 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/MC_n4_f3.tla @@ -0,0 +1,26 @@ +----------------------------- MODULE MC_n4_f3 ------------------------------- +CONSTANT Proposer \* the proposer function from 0..NRounds to 1..N + +\* the variables declared in TendermintAcc3 +VARIABLES + round, step, decision, lockedValue, lockedRound, validValue, validRound, + msgsPropose, msgsPrevote, msgsPrecommit, evidence + +\* an operator for type annotations +a <: b == a + +INSTANCE TendermintAccDebug3 WITH + Corr <- {"c1"}, + Defective <- {"a2", "a3"}, + Byzantine <- {"f4"}, + N <- 4, + T <- 1, + ValidValues <- { "v0", "v1" }, + InvalidValues <- {"v2"}, + MaxRound <- 2 + +\* run Apalache with --cinit=ConstInit +ConstInit == \* the proposer is arbitrary -- works for safety + Proposer \in [Rounds -> AllProcs] + +============================================================================= diff --git a/docs/spec/tendermint-fork-cases/MC_n5_f1.tla b/docs/spec/tendermint-fork-cases/MC_n5_f1.tla new file mode 100644 index 000000000..156675f37 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/MC_n5_f1.tla @@ -0,0 +1,26 @@ +----------------------------- MODULE MC_n5_f1 ------------------------------- +CONSTANT Proposer \* the proposer function from 0..NRounds to 1..N + +\* the variables declared in TendermintAcc3 +VARIABLES + round, step, decision, lockedValue, lockedRound, validValue, validRound, + msgsPropose, msgsPrevote, msgsPrecommit, evidence + +\* an operator for type annotations +a <: b == a + +INSTANCE TendermintAccDebug3 WITH + Corr <- {"c1", "c2", "c3", "c4"}, + Defective <- {} <: {STRING}, + Byzantine <- {"f5"}, + N <- 5, + T <- 1, + ValidValues <- { "v0", "v1" }, + InvalidValues <- {"v2"}, + MaxRound <- 2 + +\* run Apalache with --cinit=ConstInit +ConstInit == \* the proposer is arbitrary -- works for safety + Proposer \in [Rounds -> AllProcs] + +============================================================================= diff --git a/docs/spec/tendermint-fork-cases/MC_n5_f2.tla b/docs/spec/tendermint-fork-cases/MC_n5_f2.tla new file mode 100644 index 000000000..ef40158ae --- /dev/null +++ b/docs/spec/tendermint-fork-cases/MC_n5_f2.tla @@ -0,0 +1,26 @@ +----------------------------- MODULE MC_n5_f2 ------------------------------- +CONSTANT Proposer \* the proposer function from 0..NRounds to 1..N + +\* the variables declared in TendermintAcc3 +VARIABLES + round, step, decision, lockedValue, lockedRound, validValue, validRound, + msgsPropose, msgsPrevote, msgsPrecommit, evidence + +\* an operator for type annotations +a <: b == a + +INSTANCE TendermintAccDebug3 WITH + Corr <- {"c1", "c2", "c3"}, + Defective <- {"a4"}, + Byzantine <- {"f5"}, + N <- 5, + T <- 1, + ValidValues <- { "v0", "v1" }, + InvalidValues <- {"v2"}, + MaxRound <- 2 + +\* run Apalache with --cinit=ConstInit +ConstInit == \* the proposer is arbitrary -- works for safety + Proposer \in [Rounds -> AllProcs] + +============================================================================= diff --git a/docs/spec/tendermint-fork-cases/MC_n7_f2.tla b/docs/spec/tendermint-fork-cases/MC_n7_f2.tla new file mode 100644 index 000000000..ac2de9437 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/MC_n7_f2.tla @@ -0,0 +1,26 @@ +----------------------------- MODULE MC_n7_f2 ------------------------------- +CONSTANT Proposer \* the proposer function from 0..NRounds to 1..N + +\* the variables declared in TendermintAcc3 +VARIABLES + round, step, decision, lockedValue, lockedRound, validValue, validRound, + msgsPropose, msgsPrevote, msgsPrecommit, evidence + +\* an operator for type annotations +a <: b == a + +INSTANCE TendermintAccDebug3 WITH + Corr <- {"c1", "c2", "c3", "c4", "c5"}, + Defective <- {} <: {STRING}, + Byzantine <- {"f6", "f7"}, + N <- 7, + T <- 2, + ValidValues <- { "v0", "v1" }, + InvalidValues <- {"v2"}, + MaxRound <- 2 + +\* run Apalache with --cinit=ConstInit +ConstInit == \* the proposer is arbitrary -- works for safety + Proposer \in [Rounds -> AllProcs] + +============================================================================= diff --git a/docs/spec/tendermint-fork-cases/MC_n7_f3.tla b/docs/spec/tendermint-fork-cases/MC_n7_f3.tla new file mode 100644 index 000000000..32e4d4ad8 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/MC_n7_f3.tla @@ -0,0 +1,26 @@ +----------------------------- MODULE MC_n7_f3 ------------------------------- +CONSTANT Proposer \* the proposer function from 0..NRounds to 1..N + +\* the variables declared in TendermintAcc3 +VARIABLES + round, step, decision, lockedValue, lockedRound, validValue, validRound, + msgsPropose, msgsPrevote, msgsPrecommit, evidence + +\* an operator for type annotations +a <: b == a + +INSTANCE TendermintAccDebug3 WITH + Corr <- {"c1", "c2", "c3", "c4"}, + Defective <- {"f5"}, + Byzantine <- {"f6", "f7"}, + N <- 7, + T <- 2, + ValidValues <- { "v0", "v1" }, + InvalidValues <- {"v2"}, + MaxRound <- 2 + +\* run Apalache with --cinit=ConstInit +ConstInit == \* the proposer is arbitrary -- works for safety + Proposer \in [Rounds -> AllProcs] + +============================================================================= diff --git a/docs/spec/tendermint-fork-cases/MC_n7_f4.tla b/docs/spec/tendermint-fork-cases/MC_n7_f4.tla new file mode 100644 index 000000000..8a0323559 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/MC_n7_f4.tla @@ -0,0 +1,26 @@ +----------------------------- MODULE MC_n7_f4 ------------------------------- +CONSTANT Proposer \* the proposer function from 0..NRounds to 1..N + +\* the variables declared in TendermintAcc3 +VARIABLES + round, step, decision, lockedValue, lockedRound, validValue, validRound, + msgsPropose, msgsPrevote, msgsPrecommit, evidence + +\* an operator for type annotations +a <: b == a + +INSTANCE TendermintAccDebug3 WITH + Corr <- {"c1", "c2", "c3"}, + Defective <- {"f4", "f5"}, + Byzantine <- {"f6", "f7"}, + N <- 7, + T <- 2, + ValidValues <- { "v0", "v1" }, + InvalidValues <- {"v2"}, + MaxRound <- 2 + +\* run Apalache with --cinit=ConstInit +ConstInit == \* the proposer is arbitrary -- works for safety + Proposer \in [Rounds -> AllProcs] + +============================================================================= diff --git a/docs/spec/tendermint-fork-cases/README.md b/docs/spec/tendermint-fork-cases/README.md new file mode 100644 index 000000000..2e0447d15 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/README.md @@ -0,0 +1,105 @@ +# Synopsis + + A TLA+ specification of a simplified Tendermint consensus, tuned for + fork accountability. The simplifications are as follows: + + - the procotol runs for one height, that is, one-shot consensus + + - this specification focuses on safety, so timeouts are modelled with + with non-determinism + + - the proposer function is non-determinstic, no fairness is assumed + + - the messages by the faulty processes are injected right in the initial states + + - every process has the voting power of 1 + + - hashes are modelled as identity + + Having the above assumptions in mind, the specification follows the pseudo-code + of the Tendermint paper: https://arxiv.org/abs/1807.04938 + + For the purposes of fork accountability, the faulty processes are partitioned + into two sets: the Byzantine processes and the defective processes. + While the Byzantine processes can demonstrate arbitrary behavior, including + no communication, the defective processes send their messages but deviate + from the protocol in two ways: + + - Equivocation: a defective process may send two different values + in the same round. + + - Amnesia: a defective process may lock a value, although it has locked + another value in the past. + +# TLA+ modules + + - [TendermintAcc3](TendermintAcc3.tla) is the protocol specification, + + - [TendermintAccDebug3](TendermintAccDebug3.tla) contains the useful definitions + for debugging the protocol specification with TLC and Apalache, + + - [TendermintAccInv3](TendermintAccInv3.tla) contains an inductive invariant + for establishing the protocol safety as well as the forking cases, + + - `MC_n_f`, e.g., [MC_n4_f1](MC_n4_f1.tla), contains fixed constants + for model checking with Apalache + +# Reasoning about fork scenarios + +The theorem statements can be found in +[TendermintAccInv3.tla](TendermintAccInv3.tla). + +First, we would like to show that `TypedInv` is an inductive invariant. +Formally, the statement looks as follows: + +```tla +THEOREM TypedInvIsInductive == + \/ FaultyQuorum + \//\ Init => TypedInv + /\ TypedInv /\ [Next]_vars => TypedInv' +``` + +When over two-thirds of processes are faulty, `TypedInv` is not inductive. +However, there is no hope to repair the protocol in this case. We run Apalache +to prove this theorem only for fixed instances of 4 to 10 processes. Apalache +does not parse theorem statements at the moment, so we ran Apalache using a +shell script. To find a parameterized argument, one has to use a theorem +prover, e.g., TLAPS. + +Second, we would like to show that the invariant implies `Agreement`, that is, +no fork, provided that less than one third of processes is faulty. By combining +this theorem with the previous theorem, we conclude that the protocol indeed +satisfies Agreement under the condition `LessThanThirdFaulty`. + +```tla +THEOREM AgreementWhenLessThanThirdFaulty == + LessThanThirdFaulty /\ TypedInv => Agreement +``` + +Third, in the general case, we either have no fork, or two fork scenarios: + +```tla +THEOREM AgreementOrFork == + ~FaultyQuorum /\ TypedInv => AgreementOrEquivocationOrAmnesia +``` + +# Model checking results + +Check the report on [model checking with Apalache](./results/001indinv-apalache-report.md). + +TODO: re-run the experiments with the updates introduced during the dev session. + +# Running the experiments + +Run the experiments by using the script: + +```console +./run.sh +``` + +This script assumes that apalache builds are available in: + + * `~/devl/apalache-card` contains the build for the branch `ik/card`, + * `~/devl/apalache-unstable` contains the build for branch `unstable`. + + diff --git a/docs/spec/tendermint-fork-cases/TendermintAcc3.tla b/docs/spec/tendermint-fork-cases/TendermintAcc3.tla new file mode 100644 index 000000000..70826006e --- /dev/null +++ b/docs/spec/tendermint-fork-cases/TendermintAcc3.tla @@ -0,0 +1,447 @@ +----------------------------- MODULE TendermintAcc3 --------------------------- +(* + A TLA+ specification of a simplified Tendermint consensus, tuned for + fork accountability. The simplifications are as follows: + + - the protocol runs for one height, that is, it is one-shot consensus + + - this specification focuses on safety, so timeouts are modelled with + with non-determinism + + - the proposer function is non-determinstic, no fairness is assumed + + - the messages by the faulty processes are injected right in the initial states + + - every process has the voting power of 1 + + - hashes are modelled as identity + + Having the above assumptions in mind, the specification follows the pseudo-code + of the Tendermint paper: https://arxiv.org/abs/1807.04938 + + For the purposes of fork accountability, the faulty processes are partitioned + into two sets: the Byzantine processes and the defective processes. + While the Byzantine processes can demonstrate arbitrary behavior, including + no communication, the defective processes send their messages but deviate + from the protocol in two ways: + + - Equivocation: a defective process may send two different values + in the same round. + + - Amnesia: a defective process may lock a value, although it has locked + another value in the past. + + TODO: as there is no clear difference between Byzantine and Defective processes anymore, + we will probably merge them together. + + * Version 3. Modular and parameterized definitions. + * Version 2. Bugfixes in the spec and an inductive invariant. + * Version 1. A preliminary specification. + + Zarko Milosevic, Igor Konnov, 2019-2020. + *) + +EXTENDS Integers, FiniteSets + +(********************* PROTOCOL PARAMETERS **********************************) +CONSTANTS + Corr, \* the set of correct processes + Defective, \* the set of processes that show defects, e.g, amnesia or equivocation + Byzantine, \* the set of Byzantine processes, may be empty + N, \* the total number of processes: correct, defective, and Byzantine + T, \* an upper bound on the number of Byzantine processes + ValidValues, \* the set of valid values, proposed both by correct and faulty + InvalidValues, \* the set of invalid values, never proposed by the correct ones + MaxRound, \* the maximal round number + Proposer \* the proposer function from 0..NRounds to 1..N + +ASSUME(N = Cardinality(Corr \union Defective \union Byzantine)) + +(*************************** DEFINITIONS ************************************) +Faulty == Defective \union Byzantine \* the set of faulty processes +AllProcs == Corr \union Faulty \* the set of all processes +Rounds == 0..MaxRound \* the set of potential rounds +NilRound == -1 \* a special value to denote a nil round, outside of Rounds +RoundsOrNil == Rounds \union {NilRound} +Values == ValidValues \union InvalidValues \* the set of all values +NilValue == "None" \* a special value for a nil round, outside of Values +ValuesOrNil == Values \union {NilValue} + +\* a value hash is modeled as identity +Id(v) == v + +\* The validity predicate +IsValid(v) == v \in ValidValues + +\* the two thresholds that are used in the algorithm +THRESHOLD1 == T + 1 \* at least one process is not faulty +THRESHOLD2 == 2 * T + 1 \* a quorum when having N > 3 * T + +(********************* TYPE ANNOTATIONS FOR APALACHE **************************) +\* the operator for type annotations +a <: b == a + +\* the type of message records +MT == [type |-> STRING, src |-> STRING, round |-> Int, + proposal |-> STRING, validRound |-> Int, id |-> STRING] + +\* a type annotation for a message +AsMsg(m) == m <: MT +\* a type annotation for a set of messages +SetOfMsgs(S) == S <: {MT} +\* a type annotation for an empty set of messages +EmptyMsgSet == SetOfMsgs({}) + +(********************* PROTOCOL STATE VARIABLES ******************************) +VARIABLES + round, \* a process round number: Corr -> Rounds + step, \* a process step: Corr -> { "PROPOSE", "PREVOTE", "PRECOMMIT", "DECIDED" } + decision, \* process decision: Corr -> ValuesOrNil + lockedValue, \* a locked value: Corr -> ValuesOrNil + lockedRound, \* a locked round: Corr -> RoundsOrNil + validValue, \* a valid value: Corr -> ValuesOrNil + validRound \* a valid round: Corr -> RoundsOrNil + +\* book-keeping variables +VARIABLES + msgsPropose, \* PROPOSE messages broadcast in the system, Rounds -> Messages + msgsPrevote, \* PREVOTE messages broadcast in the system, Rounds -> Messages + msgsPrecommit, \* PRECOMMIT messages broadcast in the system, Rounds -> Messages + evidence \* the messages that were used by the process that made a transition + +(* to see a type invariant, check TendermintAccInv3 *) + +\* a handy definition used in UNCHANGED +vars == <> + +(********************* PROTOCOL INITIALIZATION ******************************) +FaultyProposals(r) == + SetOfMsgs([type: {"PROPOSAL"}, src: Faulty, + round: {r}, proposal: Values, validRound: RoundsOrNil]) + +AllFaultyProposals == + SetOfMsgs([type: {"PROPOSAL"}, src: Faulty, + round: Rounds, proposal: Values, validRound: RoundsOrNil]) + +FaultyPrevotes(r) == + SetOfMsgs([type: {"PREVOTE"}, src: Faulty, round: {r}, id: Values]) + +AllFaultyPrevotes == + SetOfMsgs([type: {"PREVOTE"}, src: Faulty, round: Rounds, id: Values]) + +FaultyPrecommits(r) == + SetOfMsgs([type: {"PRECOMMIT"}, src: Faulty, round: {r}, id: Values]) + +AllFaultyPrecommits == + SetOfMsgs([type: {"PRECOMMIT"}, src: Faulty, round: Rounds, id: Values]) + +BenignRoundsInMessages(msgfun) == + \* the message function never contains a message for a wrong round + \A r \in Rounds: + \A m \in msgfun[r]: + r = m.round + +\* The initial states of the protocol. Some faults can be in the system already. +Init == + /\ round = [p \in Corr |-> 0] + /\ step = [p \in Corr |-> "PROPOSE"] + /\ decision = [p \in Corr |-> NilValue] + /\ lockedValue = [p \in Corr |-> NilValue] + /\ lockedRound = [p \in Corr |-> NilRound] + /\ validValue = [p \in Corr |-> NilValue] + /\ validRound = [p \in Corr |-> NilRound] + /\ msgsPropose \in [Rounds -> SUBSET AllFaultyProposals] + /\ msgsPrevote \in [Rounds -> SUBSET AllFaultyPrevotes] + /\ msgsPrecommit \in [Rounds -> SUBSET AllFaultyPrecommits] + /\ BenignRoundsInMessages(msgsPropose) + /\ BenignRoundsInMessages(msgsPrevote) + /\ BenignRoundsInMessages(msgsPrecommit) + /\ evidence = EmptyMsgSet + +(************************ MESSAGE PASSING ********************************) +BroadcastProposal(pSrc, pRound, pProposal, pValidRound) == + LET newMsg == + AsMsg([type |-> "PROPOSAL", src |-> pSrc, round |-> pRound, + proposal |-> pProposal, validRound |-> pValidRound]) + IN + msgsPropose' = [msgsPropose EXCEPT ![pRound] = msgsPropose[pRound] \cup {newMsg}] + +BroadcastPrevote(pSrc, pRound, pId) == + LET newMsg == AsMsg([type |-> "PREVOTE", + src |-> pSrc, round |-> pRound, id |-> pId]) + IN + msgsPrevote' = [msgsPrevote EXCEPT ![pRound] = msgsPrevote[pRound] \cup {newMsg}] + +BroadcastPrecommit(pSrc, pRound, pId) == + LET newMsg == AsMsg([type |-> "PRECOMMIT", + src |-> pSrc, round |-> pRound, id |-> pId]) + IN + msgsPrecommit' = [msgsPrecommit EXCEPT ![pRound] = msgsPrecommit[pRound] \cup {newMsg}] + + +(********************* PROTOCOL TRANSITIONS ******************************) +\* lines 12-13 +StartRound(p, r) == + /\ step[p] /= "DECIDED" \* a decided process does not participate in consensus + /\ round' = [round EXCEPT ![p] = r] + /\ step' = [step EXCEPT ![p] = "PROPOSE"] + +\* lines 14-19, a proposal may be sent later +InsertProposal(p) == + LET r == round[p] IN + /\ p = Proposer[r] + /\ step[p] = "PROPOSE" + \* if the proposer is sending a proposal, then there are no other proposals + \* by the correct processes for the same round + /\ \A m \in msgsPropose[r]: m.src /= p + /\ \E v \in ValidValues: + LET proposal == IF validValue[p] /= NilValue THEN validValue[p] ELSE v IN + BroadcastProposal(p, round[p], proposal, validRound[p]) + /\ evidence' = EmptyMsgSet + /\ UNCHANGED <> + +\* lines 22-27 +UponProposalInPropose(p) == + \E v \in Values: + /\ step[p] = "PROPOSE" (* line 22 *) + /\ LET msg == + AsMsg([type |-> "PROPOSAL", src |-> Proposer[round[p]], + round |-> round[p], proposal |-> v, validRound |-> NilRound]) IN + /\ msg \in msgsPropose[round[p]] \* line 22 + /\ evidence' = {msg} + /\ LET mid == (* line 23 *) + IF IsValid(v) /\ (lockedRound[p] = NilRound \/ lockedValue[p] = v) + THEN Id(v) + ELSE NilValue + IN + BroadcastPrevote(p, round[p], mid) \* lines 24-26 + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 28-33 +UponProposalInProposeAndPrevote(p) == + \E v \in Values, vr \in Rounds: + /\ step[p] = "PROPOSE" /\ 0 <= vr /\ vr < round[p] \* line 28, the while part + /\ LET msg == + AsMsg([type |-> "PROPOSAL", src |-> Proposer[round[p]], + round |-> round[p], proposal |-> v, validRound |-> vr]) + IN + /\ msg \in msgsPropose[round[p]] \* line 28 + /\ LET PV == { m \in msgsPrevote[vr]: m.id = Id(v) } IN + /\ Cardinality(PV) >= THRESHOLD2 \* line 28 + /\ evidence' = PV \union {msg} + /\ LET mid == (* line 29 *) + IF IsValid(v) /\ (lockedRound[p] <= vr \/ lockedValue[p] = v) + THEN Id(v) + ELSE NilValue + IN + BroadcastPrevote(p, round[p], mid) \* lines 24-26 + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + + \* lines 34-35 + lines 61-64 (onTimeoutPrevote) +UponQuorumOfPrevotesAny(p) == + /\ step[p] = "PREVOTE" \* line 34 and 61 + /\ Cardinality(msgsPrevote[round[p]]) >= THRESHOLD2 \* line 34 + \* multiple messages from a process may trigger this rule (no effect on safety) + /\ evidence' = msgsPrevote[round[p]] + /\ BroadcastPrecommit(p, round[p], NilValue) + /\ step' = [step EXCEPT ![p] = "PRECOMMIT"] + /\ UNCHANGED <> + +\* lines 36-46 +UponProposalInPrevoteOrCommitAndPrevote(p) == + \E v \in ValidValues, vr \in RoundsOrNil: + /\ step[p] \in {"PREVOTE", "PRECOMMIT"} \* line 36 + /\ LET msg == + AsMsg([type |-> "PROPOSAL", src |-> Proposer[round[p]], + round |-> round[p], proposal |-> v, validRound |-> vr]) IN + /\ msg \in msgsPropose[round[p]] \* line 36 + /\ LET PV == { m \in msgsPrevote[round[p]]: m.id = Id(v) } IN + /\ Cardinality(PV) >= THRESHOLD2 \* line 36 + /\ evidence' = PV \union {msg} + /\ IF step[p] = "PREVOTE" + THEN \* lines 38-41: + /\ lockedValue' = [lockedValue EXCEPT ![p] = v] + /\ lockedRound' = [lockedRound EXCEPT ![p] = round[p]] + /\ BroadcastPrecommit(p, round[p], Id(v)) + /\ step' = [step EXCEPT ![p] = "PRECOMMIT"] + ELSE + UNCHANGED <> + \* lines 42-43 + /\ validValue' = [validValue EXCEPT ![p] = v] + /\ validRound' = [validRound EXCEPT ![p] = round[p]] + /\ UNCHANGED <> + +\* lines 47-48 + 65-67 (onTimeoutPrecommit) +UponQuorumOfPrecommitsAny(p) == + /\ Cardinality(msgsPrecommit[round[p]]) >= THRESHOLD2 \* line 47 + /\ evidence' = msgsPrecommit[round[p]] + /\ round[p] + 1 \in Rounds + /\ StartRound(p, round[p] + 1) + /\ UNCHANGED <> + +\* lines 49-54 +UponProposalInPrecommitNoDecision(p) == + /\ decision[p] = NilValue \* line 49 + /\ \E v \in ValidValues (* line 50*) , r \in Rounds, vr \in RoundsOrNil: + /\ LET msg == AsMsg([type |-> "PROPOSAL", src |-> Proposer[r], + round |-> r, proposal |-> v, validRound |-> vr]) IN + /\ msg \in msgsPropose[r] \* line 49 + /\ LET PV == { m \in msgsPrecommit[r]: m.id = Id(v) } IN + /\ Cardinality(PV) >= THRESHOLD2 \* line 49 + /\ evidence' = PV \union {msg} + /\ decision' = [decision EXCEPT ![p] = v] \* update the decision, line 51 + \* The original algorithm does not have 'DECIDED', but it increments the height. + \* We introduced 'DECIDED' here to prevent the process from changing its decision. + /\ step' = [step EXCEPT ![p] = "DECIDED"] + /\ UNCHANGED <> + +\* the actions below are not essential for safety, but added for completeness + +\* lines 20-21 + 57-60 +OnTimeoutPropose(p) == + /\ step[p] = "PROPOSE" + /\ p /= Proposer[round[p]] + /\ BroadcastPrevote(p, round[p], NilValue) + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 44-46 +OnQuoromOfNilPrevotes(p) == + /\ step[p] = "PREVOTE" + /\ LET PV == { m \in msgsPrevote[round[p]]: m.id = Id(NilValue) } IN + /\ Cardinality(PV) >= THRESHOLD2 \* line 36 + /\ evidence' = PV + /\ BroadcastPrecommit(p, round[p], Id(NilValue)) + /\ step' = [step EXCEPT ![p] = "PREVOTE"] + /\ UNCHANGED <> + +\* lines 55-56 +OnRoundCatchup(p) == + \E r \in {rr \in Rounds: rr > round[p]}: + /\ LET RM == msgsPropose[r] \union msgsPrevote[r] \union msgsPrecommit[r] IN + /\ Cardinality(RM) >= THRESHOLD1 + /\ evidence' = RM + /\ StartRound(p, r) + /\ UNCHANGED <> + +(* + * A system transition. In this specificatiom, the system may eventually deadlock, + * e.g., when all processes decide. This is expected behavior, as we focus on safety. + *) +Next == + \E p \in Corr: + \/ InsertProposal(p) + \/ UponProposalInPropose(p) + \/ UponProposalInProposeAndPrevote(p) + \/ UponQuorumOfPrevotesAny(p) + \/ UponProposalInPrevoteOrCommitAndPrevote(p) + \/ UponQuorumOfPrecommitsAny(p) + \/ UponProposalInPrecommitNoDecision(p) + \* the actions below are not essential for safety, but added for completeness + \/ OnTimeoutPropose(p) + \/ OnQuoromOfNilPrevotes(p) + \/ OnRoundCatchup(p) + +(**************************** FORK SCENARIOS ***************************) +\* a state that has at least one equivocation +Equivocation == + \E r \in Rounds: + \/ \E m1, m2 \in msgsPropose[r]: + m1 /= m2 /\ m1.src = m2.src + \/ \E m1, m2 \in msgsPrevote[r]: + m1 /= m2 /\ m1.src = m2.src + \/ \E m1, m2 \in msgsPrecommit[r]: + m1 /= m2 /\ m1.src = m2.src + +\* equivocation by amnesic processes +EquivocationBy(p) == + \E r \in Rounds: + \/ \E m1, m2 \in msgsPropose[r]: + m1.proposal /= m2.proposal /\ m1.src = p /\ m2.src = p + \/ \E m1, m2 \in msgsPrevote[r]: + m1.id /= m2.id /\ m1.src = p /\ m2.src = p + \/ \E m1, m2 \in msgsPrecommit[r]: + m1.id /= m2.id /\ m1.src = p /\ m2.src = p + +\* amnesic behavior by a process p +AmnesiaBy(p) == + \E r1, r2 \in Rounds: + /\ r1 < r2 + /\ \E v1, v2 \in ValidValues: + /\ v1 /= v2 + /\ AsMsg([type |-> "PRECOMMIT", src |-> p, + round |-> r1, id |-> Id(v1)]) \in msgsPrecommit[r1] + /\ AsMsg([type |-> "PREVOTE", src |-> p, + round |-> r2, id |-> Id(v2)]) \in msgsPrecommit[r2] + /\ \A r \in { rnd \in Rounds: r1 <= rnd /\ rnd <= r2 }: + LET prevotes == + { m \in msgsPrevote[r]: + m.type = "PREVOTE" /\ m.round = r /\ m.id = Id(v2) } + IN + Cardinality(prevotes) < THRESHOLD2 + +\* Exclude the equivocation states, that is, +\* exclude the equivocal messages by the faulty processes +InitNoEquivocation == + Init /\ ~Equivocation + +(******************************** PROPERTIES ***************************************) + +\* the safety property -- agreement +Agreement == \A p, q \in Corr: + \/ decision[p] = NilValue + \/ decision[q] = NilValue + \/ decision[p] = decision[q] + +\* the protocol validity +Validity == + \A p \in Corr: decision[p] \in ValidValues \union {NilValue} + +\* either agreement holds, or the amnesic processes indeed have amnesia +AgreementOrAmnesia == + Agreement \/ (\A p \in Defective: AmnesiaBy(p)) + +\* the strong agreement property that also assumes no amnesia +AgreementNoAmnesia == + Agreement /\ \A p \in Defective: ~AmnesiaBy(p) + +(* + The protocol safety. Three cases are possible: + 1. There is no fork, that is, Agreement holds true. + 2. The amnesic processes have sent equivocal messages. + 3. The amnesic processes have sent messages that prove amnesia. + + This property seems to be unrealistic. See AgreementOrEquivocationOrAmnesia. + *) +AgreementOrEquivocationOrAmnesiaOld == + \/ Agreement + \/ \A p \in Defective: EquivocationBy(p) + \/ \A p \in Defective: AmnesiaBy(p) + +(* + The protocol safety. Two cases are possible: + 1. There is no fork, that is, Agreement holds true. + 2. A subset of faulty processes demonstrates equivocation or amnesia. + *) +AgreementOrEquivocationOrAmnesia == + \/ Agreement + \/ \E Detectable \in SUBSET Faulty: + /\ Cardinality(Detectable) >= THRESHOLD1 + /\ \A p \in Detectable: + EquivocationBy(p) \/ AmnesiaBy(p) + + +============================================================================= + diff --git a/docs/spec/tendermint-fork-cases/TendermintAccDebug3.tla b/docs/spec/tendermint-fork-cases/TendermintAccDebug3.tla new file mode 100644 index 000000000..3b03fd9c9 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/TendermintAccDebug3.tla @@ -0,0 +1,100 @@ +----------------------- MODULE TendermintAccDebug3 ----------------------------- +(* + A few definitions that we use for debugging TendermintAcc3, which do not belong + to the specification itself. + + * Version 3. Modular and parameterized definitions. + + Igor Konnov, 2020. + *) + +EXTENDS TendermintAccInv3 + +\* make them parameters? +NFaultyProposals == 0 \* the number of injected faulty PROPOSE messages +NFaultyPrevotes == 6 \* the number of injected faulty PREVOTE messages +NFaultyPrecommits == 6 \* the number of injected faulty PRECOMMIT messages + +\* Given a set of allowed messages Msgs, this operator produces a function from +\* rounds to sets of messages. +\* Importantly, there will be exactly k messages in the image of msgFun. +\* We use this action to produce k faults in an initial state. +ProduceFaults(msgFun, From, k) == + \E f \in [1..k -> From]: + msgFun = [r \in Rounds |-> {m \in {f[i]: i \in 1..k}: m.round = r}] + +\* As TLC explodes with faults, we may have initial states without faults +InitNoFaults == + /\ round = [p \in Corr |-> 0] + /\ step = [p \in Corr |-> "PROPOSE"] + /\ decision = [p \in Corr |-> NilValue] + /\ lockedValue = [p \in Corr |-> NilValue] + /\ lockedRound = [p \in Corr |-> NilRound] + /\ validValue = [p \in Corr |-> NilValue] + /\ validRound = [p \in Corr |-> NilRound] + /\ msgsPropose = [r \in Rounds |-> EmptyMsgSet] + /\ msgsPrevote = [r \in Rounds |-> EmptyMsgSet] + /\ msgsPrecommit = [r \in Rounds |-> EmptyMsgSet] + /\ evidence = EmptyMsgSet + +(* + A specialized version of Init that injects NFaultyProposals proposals, + NFaultyPrevotes prevotes, NFaultyPrecommits precommits by the faulty processes + *) +InitFewFaults == + /\ round = [p \in Corr |-> 0] + /\ step = [p \in Corr |-> "PROPOSE"] + /\ decision = [p \in Corr |-> NilValue] + /\ lockedValue = [p \in Corr |-> NilValue] + /\ lockedRound = [p \in Corr |-> NilRound] + /\ validValue = [p \in Corr |-> NilValue] + /\ validRound = [p \in Corr |-> NilRound] + /\ ProduceFaults(msgsPrevote', + SetOfMsgs([type: {"PREVOTE"}, src: Faulty, round: Rounds, id: Values]), + NFaultyPrevotes) + /\ ProduceFaults(msgsPrecommit', + SetOfMsgs([type: {"PRECOMMIT"}, src: Faulty, round: Rounds, id: Values]), + NFaultyPrecommits) + /\ ProduceFaults(msgsPropose', + SetOfMsgs([type: {"PROPOSAL"}, src: Faulty, round: Rounds, + proposal: Values, validRound: Rounds \cup {NilRound}]), + NFaultyProposals) + /\ evidence = EmptyMsgSet + +\* Add faults incrementally +NextWithFaults == + \* either the protocol makes a step + \/ Next + \* or a faulty process sends a message + \//\ UNCHANGED <> + /\ \E p \in Faulty: + \E r \in Rounds: + \//\ UNCHANGED <> + /\ \E proposal \in ValidValues \union {NilValue}: + \E vr \in RoundsOrNil: + BroadcastProposal(p, r, proposal, vr) + \//\ UNCHANGED <> + /\ \E id \in ValidValues \union {NilValue}: + BroadcastPrevote(p, r, id) + \//\ UNCHANGED <> + /\ \E id \in ValidValues \union {NilValue}: + BroadcastPrecommit(p, r, id) + +(******************************** PROPERTIES ***************************************) +\* simple reachability properties to see that the spec is progressing +NoPrevote == \A p \in Corr: step[p] /= "PREVOTE" + +NoPrecommit == \A p \in Corr: step[p] /= "PRECOMMIT" + +NoValidPrecommit == + \A r \in Rounds: + \A m \in msgsPrecommit[r]: + m.id = NilValue \/ m.src \in Faulty + +NoHigherRounds == \A p \in Corr: round[p] < 1 + +NoDecision == \A p \in Corr: decision[p] = NilValue + +============================================================================= + diff --git a/docs/spec/tendermint-fork-cases/TendermintAccInv3.tla b/docs/spec/tendermint-fork-cases/TendermintAccInv3.tla new file mode 100644 index 000000000..8acd266c5 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/TendermintAccInv3.tla @@ -0,0 +1,323 @@ +------------------------- MODULE TendermintAccInv3 ---------------------------- +(* + An inductive invariant for TendermintAcc3, which capture the forked + and non-forked cases. + + * Version 3. Modular and parameterized definitions. + * Version 2. Bugfixes in the spec and an inductive invariant. + + Igor Konnov, 2020. + *) + +EXTENDS TendermintAcc3 + +(************************** TYPE INVARIANT ***********************************) +(* first, we define the sets of all potential messages *) +AllProposals == + [type: {"PROPOSAL"}, + src: AllProcs, + round: Rounds, + proposal: ValuesOrNil, + validRound: RoundsOrNil] <: {MT} + +AllPrevotes == + [type: {"PREVOTE"}, + src: AllProcs, + round: Rounds, + id: ValuesOrNil] <: {MT} + +AllPrecommits == + [type: {"PRECOMMIT"}, + src: AllProcs, + round: Rounds, + id: ValuesOrNil] <: {MT} + +(* the standard type invariant -- importantly, it is inductive *) +TypeOK == + /\ round \in [Corr -> Rounds] + /\ step \in [Corr -> { "PROPOSE", "PREVOTE", "PRECOMMIT", "DECIDED" }] + /\ decision \in [Corr -> ValidValues \union {NilValue}] + /\ lockedValue \in [Corr -> ValidValues \union {NilValue}] + /\ lockedRound \in [Corr -> RoundsOrNil] + /\ validValue \in [Corr -> ValidValues \union {NilValue}] + /\ validRound \in [Corr -> RoundsOrNil] + /\ msgsPropose \in [Rounds -> SUBSET AllProposals] + /\ BenignRoundsInMessages(msgsPropose) + /\ msgsPrevote \in [Rounds -> SUBSET AllPrevotes] + /\ BenignRoundsInMessages(msgsPrevote) + /\ msgsPrecommit \in [Rounds -> SUBSET AllPrecommits] + /\ BenignRoundsInMessages(msgsPrecommit) + /\ evidence \in SUBSET (AllProposals \union AllPrevotes \union AllPrecommits) + +(************************** INDUCTIVE INVARIANT *******************************) + +NoFutureMessagesForLargerRounds(p) == + \* a correct process does not send messages for the future rounds + \A r \in { rr \in Rounds: rr > round[p] }: + /\ \A m \in msgsPropose[r]: m.src /= p + /\ \A m \in msgsPrevote[r]: m.src /= p + /\ \A m \in msgsPrecommit[r]: m.src /= p + +NoFutureMessagesForCurrentRound(p) == + \* a correct process does not send messages in the future + LET r == round[p] IN + /\ Proposer[r] = p \/ \A m \in msgsPropose[r]: m.src /= p + /\ \/ step[p] \in {"PREVOTE", "PRECOMMIT", "DECIDED"} + \/ \A m \in msgsPrevote[r]: m.src /= p + /\ \/ step[p] \in {"PRECOMMIT", "DECIDED"} + \/ \A m \in msgsPrecommit[r]: m.src /= p + +\* the correct processes never send future messages +AllNoFutureMessagesSent == + \A p \in Corr: + /\ NoFutureMessagesForCurrentRound(p) + /\ NoFutureMessagesForLargerRounds(p) + +\* a correct process in the PREVOTE state has sent a PREVOTE message +IfInPrevoteThenSentPrevote(p) == + step[p] = "PREVOTE" => + \E m \in msgsPrevote[round[p]]: + /\ m.id \in ValidValues \cup { NilValue } + /\ m.src = p + +AllIfInPrevoteThenSentPrevote == + \A p \in Corr: IfInPrevoteThenSentPrevote(p) + +\* a correct process in the PRECOMMIT state has sent a PRECOMMIT message +IfInPrecommitThenSentPrecommit(p) == + step[p] = "PRECOMMIT" => + \E m \in msgsPrecommit[round[p]]: + /\ m.id \in ValidValues \cup { NilValue } + /\ m.src = p + +AllIfInPrecommitThenSentPrecommit == + \A p \in Corr: IfInPrecommitThenSentPrecommit(p) + +\* a process in the PRECOMMIT state has sent a PRECOMMIT message +IfInDecidedThenValidDecision(p) == + step[p] = "DECIDED" <=> decision[p] \in ValidValues + +AllIfInDecidedThenValidDecision == + \A p \in Corr: IfInDecidedThenValidDecision(p) + +\* a decided process should have received a proposal on its decision +IfInDecidedThenReceivedProposal(p) == + step[p] = "DECIDED" => + \E r \in Rounds: \* r is not necessarily round[p] + /\ \E m \in msgsPropose[r]: + /\ m.src = Proposer[r] + /\ m.proposal = decision[p] + \* not inductive: /\ m.src \in Corr => (m.validRound <= r) + +AllIfInDecidedThenReceivedProposal == + \A p \in Corr: IfInDecidedThenReceivedProposal(p) + +\* a decided process has received two-thirds of precommit messages +IfInDecidedThenReceivedTwoThirds(p) == + step[p] = "DECIDED" => + \E r \in Rounds: + LET PV == { m \in msgsPrecommit[r]: m.id = decision[p] } IN + Cardinality(PV) >= THRESHOLD2 + +AllIfInDecidedThenReceivedTwoThirds == + \A p \in Corr: IfInDecidedThenReceivedTwoThirds(p) + +\* for a round r, there is proposal by the round proposer for a valid round vr +ProposalInRound(r, proposedVal, vr) == + \E m \in msgsPropose[r]: + /\ m.src = Proposer[r] + /\ m.proposal = proposedVal + /\ m.validRound = vr + +TwoThirdsPrevotes(vr, v) == + LET PV == { mm \in msgsPrevote[vr]: mm.id = v } IN + Cardinality(PV) >= THRESHOLD2 + +\* if a process sends a PREVOTE, then there are three possibilities: +\* 1) the process is faulty, 2) the PREVOTE cotains Nil, +\* 3) there is a proposal in an earlier (valid) round and two thirds of PREVOTES +IfSentPrevoteThenReceivedProposalOrTwoThirds(r) == + \A mpv \in msgsPrevote[r]: + \/ mpv.src \in Faulty + \* lockedRound and lockedValue is beyond my comprehension + \/ mpv.id = NilValue + \//\ mpv.src \in Corr + /\ mpv.id /= NilValue + /\ \/ ProposalInRound(r, mpv.id, NilRound) + \/ \E vr \in { rr \in Rounds: rr < r }: + /\ ProposalInRound(r, mpv.id, vr) + /\ TwoThirdsPrevotes(vr, mpv.id) + +AllIfSentPrevoteThenReceivedProposalOrTwoThirds == + \A r \in Rounds: + IfSentPrevoteThenReceivedProposalOrTwoThirds(r) + +\* if a correct process has sent a PRECOMMIT, then there are two thirds, +\* either on a valid value, or a nil value +IfSentPrecommitThenReceivedTwoThirds == + \A r \in Rounds: + \A mpc \in msgsPrecommit[r]: + \/ mpc.src \in Faulty + \/ /\ mpc.src \in Corr + /\ \/ /\ mpc.id \in ValidValues + /\ LET PV == { m \in msgsPrevote[r]: m.id = mpc.id } IN + Cardinality(PV) >= THRESHOLD2 + \/ /\ mpc.id = NilValue + /\ Cardinality(msgsPrevote[r]) >= THRESHOLD2 + +\* there is a locked round if a only if there is a locked value +LockedRoundIffLockedValue(p) == + (lockedRound[p] = NilRound) <=> (lockedValue[p] = NilValue) + +AllLockedRoundIffLockedValue == + \A p \in Corr: LockedRoundIffLockedValue(p) + +\* when a process locked a round, it should have seen a precommit on a locked value +IfLockedRoundThenSentCommit(p) == + lockedRound[p] /= NilRound + => \E r \in { rr \in Rounds: rr <= round[p] }: + \E m \in msgsPrecommit[r]: + m.src = p /\ m.id = lockedValue[p] + +AllIfLockedRoundThenSentCommit == + \A p \in Corr: IfLockedRoundThenSentCommit(p) + +\* a process always locks the latest round, for which it has sent a PRECOMMIT +LatestPrecommitHasLockedRound(p) == + LET pPrecommits == {mm \in UNION { msgsPrecommit[r]: r \in Rounds }: mm.src = p } IN + pPrecommits /= {} <: {MT} + => LET latest == + CHOOSE m \in pPrecommits: + \A m2 \in pPrecommits: + m2.round < m.round + IN + /\ lockedRound[p] = latest.round + /\ lockedValue[p] = latest.id + +AllLatestPrecommitHasLockedRound == + \A p \in Corr: + LatestPrecommitHasLockedRound(p) + +\* Every correct process sends only one value or NilValue. +\* This test has quantifier alternation -- a threat to all decision procedures. +\* Luckily, the sets Corr and ValidValues are small. +NoEquivocationByCorrect(r, msgs) == + \A p \in Corr: + \E v \in ValidValues \union {NilValue}: + \A m \in msgs[r]: + \/ m.src /= p + \/ m.id = v + +\* a proposer nevers sends two values +ProposalsByProposer(r, msgs) == + \* if the proposer is not faulty, it sends only one value + \E v \in ValidValues: + \A m \in msgs[r]: + \/ m.src \in Faulty + \/ m.src = Proposer[r] /\ m.proposal = v + +AllNoEquivocationByCorrect == + \A r \in Rounds: + /\ ProposalsByProposer(r, msgsPropose) + /\ NoEquivocationByCorrect(r, msgsPrevote) + /\ NoEquivocationByCorrect(r, msgsPrecommit) + +\* construct the set of the message senders +Senders(M) == { m.src: m \in M } + +\* The final piece by Josef Widder: +\* if T + 1 processes precommit on the same value in a round, +\* then in the future rounds there are less than 2T + 1 prevotes for another value +PrecommitsLockValue == + \A r \in Rounds: + \A v \in ValidValues \union {NilValue}: + \/ Cardinality(Senders({m \in msgsPrecommit[r]: m.id = v})) < THRESHOLD1 + \/ \A fr \in { rr \in Rounds: rr > r }: \* future rounds + \A w \in (ValuesOrNil) \ {v}: + Cardinality(Senders({m \in msgsPrevote[fr]: m.id = w})) < THRESHOLD2 + +\* a combination of all lemmas +Inv == + /\ AllNoFutureMessagesSent + /\ AllIfInPrevoteThenSentPrevote + /\ AllIfInPrecommitThenSentPrecommit + /\ AllIfInDecidedThenReceivedProposal + /\ AllIfInDecidedThenReceivedTwoThirds + /\ AllIfInDecidedThenValidDecision + /\ AllLockedRoundIffLockedValue + /\ AllIfLockedRoundThenSentCommit + /\ AllLatestPrecommitHasLockedRound + /\ AllIfSentPrevoteThenReceivedProposalOrTwoThirds + /\ IfSentPrecommitThenReceivedTwoThirds + /\ AllNoEquivocationByCorrect + /\ PrecommitsLockValue + +\* this is the inductive invariant we like to check +TypedInv == TypeOK /\ Inv + +\* UNUSED FOR SAFETY +ValidRoundNotSmallerThanLockedRound(p) == + validRound[p] >= lockedRound[p] + +\* UNUSED FOR SAFETY +ValidRoundIffValidValue(p) == + (validRound[p] = NilRound) <=> (validValue[p] = NilValue) + +\* UNUSED FOR SAFETY +AllValidRoundIffValidValue == + \A p \in Corr: ValidRoundIffValidValue(p) + +\* if validRound is defined, then there are two-thirds of PREVOTEs +IfValidRoundThenTwoThirds(p) == + \/ validRound[p] = NilRound + \/ LET PV == { m \in msgsPrevote[validRound[p]]: m.id = validValue[p] } IN + Cardinality(PV) >= THRESHOLD2 + +\* UNUSED FOR SAFETY +AllIfValidRoundThenTwoThirds == + \A p \in Corr: IfValidRoundThenTwoThirds(p) + +\* a valid round can be only set to a valid value that was proposed earlier +IfValidRoundThenProposal(p) == + \/ validRound[p] = NilRound + \/ \E m \in msgsPropose[validRound[p]]: + m.proposal = validValue[p] + +\* UNUSED FOR SAFETY +AllIfValidRoundThenProposal == + \A p \in Corr: IfValidRoundThenProposal(p) + +(******************************** THEOREMS ***************************************) +(* Under this condition, the faulty processes can decide alone *) +FaultyQuorum == Cardinality(Faulty) >= THRESHOLD2 + +(* The standard condition of the Tendermint security model *) +LessThanThirdFaulty == N > 3 * T /\ Cardinality(Faulty) <= T + +(* + TypedInv is an inductive invariant, provided that there is no faulty quorum. + We run Apalache to prove this theorem only for fixed instances of 4 to 10 processes. + (We run Apalache manually, as it does not parse theorem statements at the moment.) + To get a parameterized argument, one has to use a theorem prover, e.g., TLAPS. + *) +THEOREM TypedInvIsInductive == + \/ FaultyQuorum \* if there are 2 * T + 1 faulty processes, we give up + \//\ Init => TypedInv + /\ TypedInv /\ [Next]_vars => TypedInv' + +(* + There should be no fork, when there are less than 1/3 faulty processes. + *) +THEOREM AgreementWhenLessThanThirdFaulty == + LessThanThirdFaulty /\ TypedInv => Agreement + +(* + In a more general case, when there are less than 2/3 faulty processes, + there is either no fork, or two scenarios exist: + equivocation by Amnesic, or amnesia by Amnesic. + *) +THEOREM AgreementOrFork == + ~FaultyQuorum /\ TypedInv => AgreementOrEquivocationOrAmnesia + +============================================================================= + diff --git a/docs/spec/tendermint-fork-cases/apalache.properties b/docs/spec/tendermint-fork-cases/apalache.properties new file mode 100644 index 000000000..83a7e2627 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/apalache.properties @@ -0,0 +1,11 @@ +search.idle.timeout=60 +search.split.timeout.minimum=3600 +search.split.timeout.factor=2000 +#search.split.timeout.minimum=30 +#search.split.timeout.factor=130 +#search.split.timeout.minimum=600 +#search.split.timeout.factor=170 +#f=(8|9|10) +#search.transitionFilter=0,${f},${f},${f},${f},${f},${f},${f},${f},${f},2,0,(3|5),7,0,(3|5),7 +#search.invariantFilter=16 +#search.transitionFilter=0,[^5],[^5],[^5],[^5],[^5],[^5],[^5],[^5],[^5],[^5],5 diff --git a/docs/spec/tendermint-fork-cases/counterexample-vc0-w1.tla b/docs/spec/tendermint-fork-cases/counterexample-vc0-w1.tla new file mode 100644 index 000000000..76414d16b --- /dev/null +++ b/docs/spec/tendermint-fork-cases/counterexample-vc0-w1.tla @@ -0,0 +1,4009 @@ +------------------------- MODULE Counterexample ------------------------- + +\* Transition 0: State 0 to State 1: + +ConstInit == Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "f3" + +\* Transition 0: State 0 to State 1: + +State1 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "f3" + /\ decision = "c1" :> "None" @@ "c2" :> "None" + /\ evidence = {} + /\ lockedRound = "c1" :> -1 @@ "c2" :> -1 + /\ lockedValue = "c1" :> "None" @@ "c2" :> "None" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 0 + /\ step = "c1" :> "PROPOSE" @@ "c2" :> "PROPOSE" + /\ validRound = "c1" :> -1 @@ "c2" :> -1 + /\ validValue = "c1" :> "None" @@ "c2" :> "None" + +\* Transition 0: State 1 to State 2: + +State2 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "f3" + /\ decision = "c1" :> "None" @@ "c2" :> "None" + /\ evidence + = {[proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1]} + /\ lockedRound = "c1" :> -1 @@ "c2" :> -1 + /\ lockedValue = "c1" :> "None" @@ "c2" :> "None" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 0 + /\ step = "c1" :> "PROPOSE" @@ "c2" :> "PREVOTE" + /\ validRound = "c1" :> -1 @@ "c2" :> -1 + /\ validValue = "c1" :> "None" @@ "c2" :> "None" + +\* Transition 5: State 2 to State 3: + +State3 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "f3" + /\ decision = "c1" :> "None" @@ "c2" :> "None" + /\ evidence + = { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ lockedRound = "c1" :> -1 @@ "c2" :> -1 + /\ lockedValue = "c1" :> "None" @@ "c2" :> "None" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 2 @@ "c2" :> 0 + /\ step = "c1" :> "PROPOSE" @@ "c2" :> "PREVOTE" + /\ validRound = "c1" :> -1 @@ "c2" :> -1 + /\ validValue = "c1" :> "None" @@ "c2" :> "None" + +\* Transition 9: State 3 to State 4: + +State4 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "f3" + /\ decision = "c1" :> "None" @@ "c2" :> "None" + /\ evidence + = { [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0] } + /\ lockedRound = "c1" :> -1 @@ "c2" :> 0 + /\ lockedValue = "c1" :> "None" @@ "c2" :> "v1" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 2 @@ "c2" :> 0 + /\ step = "c1" :> "PROPOSE" @@ "c2" :> "PRECOMMIT" + /\ validRound = "c1" :> -1 @@ "c2" :> 0 + /\ validValue = "c1" :> "None" @@ "c2" :> "v1" + +\* Transition 0: State 4 to State 5: + +State5 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "f3" + /\ decision = "c1" :> "None" @@ "c2" :> "None" + /\ evidence + = {[proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1]} + /\ lockedRound = "c1" :> -1 @@ "c2" :> 0 + /\ lockedValue = "c1" :> "None" @@ "c2" :> "v1" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 2 @@ "c2" :> 0 + /\ step = "c1" :> "PREVOTE" @@ "c2" :> "PRECOMMIT" + /\ validRound = "c1" :> -1 @@ "c2" :> 0 + /\ validValue = "c1" :> "None" @@ "c2" :> "v1" + +\* Transition 5: State 5 to State 6: + +State6 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "f3" + /\ decision = "c1" :> "None" @@ "c2" :> "v1" + /\ evidence + = { [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1] } + /\ lockedRound = "c1" :> -1 @@ "c2" :> 0 + /\ lockedValue = "c1" :> "None" @@ "c2" :> "v1" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 2 @@ "c2" :> 0 + /\ step = "c1" :> "PREVOTE" @@ "c2" :> "DECIDED" + /\ validRound = "c1" :> -1 @@ "c2" :> 0 + /\ validValue = "c1" :> "None" @@ "c2" :> "v1" + +\* Transition 7: State 6 to State 7: + +State7 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "f3" + /\ decision = "c1" :> "None" @@ "c2" :> "v1" + /\ evidence + = { [id |-> "v0", round |-> 2, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1] } + /\ lockedRound = "c1" :> 2 @@ "c2" :> 0 + /\ lockedValue = "c1" :> "v0" @@ "c2" :> "v1" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 2 @@ "c2" :> 0 + /\ step = "c1" :> "PRECOMMIT" @@ "c2" :> "DECIDED" + /\ validRound = "c1" :> 2 @@ "c2" :> 0 + /\ validValue = "c1" :> "v0" @@ "c2" :> "v1" + +\* Transition 0: State 7 to State 8: + +State8 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "f3" + /\ decision = "c1" :> "None" @@ "c2" :> "v1" + /\ evidence + = { [id |-> "v0", round |-> 2, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1] } + /\ lockedRound = "c1" :> 2 @@ "c2" :> 0 + /\ lockedValue = "c1" :> "v0" @@ "c2" :> "v1" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 2 @@ "c2" :> 0 + /\ step = "c1" :> "PRECOMMIT" @@ "c2" :> "DECIDED" + /\ validRound = "c1" :> 2 @@ "c2" :> 0 + /\ validValue = "c1" :> "v0" @@ "c2" :> "v1" + +\* Transition 2: State 8 to State 9: + +State9 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "f3" + /\ decision = "c1" :> "v0" @@ "c2" :> "v1" + /\ evidence + = { [id |-> "v0", round |-> 2, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ lockedRound = "c1" :> 2 @@ "c2" :> 0 + /\ lockedValue = "c1" :> "v0" @@ "c2" :> "v1" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 2 @@ "c2" :> 0 + /\ step = "c1" :> "DECIDED" @@ "c2" :> "DECIDED" + /\ validRound = "c1" :> 2 @@ "c2" :> 0 + /\ validValue = "c1" :> "v0" @@ "c2" :> "v1" + +(* The following formula holds true in State9 and violates the invariant *) +InvariantViolation == + BMC!Skolem((\E p$20 \in { "c1", "c2" }: + BMC!Skolem((\E q$2 \in { "c1", "c2" }: + ~(decision[p$20] = "None") + /\ ~(decision[q$2] = "None") + /\ ~(decision[p$20] = decision[q$2]))))) +================================================================================ +\* Created Tue Mar 10 18:32:04 CET 2020 by Apalache +\* https://github.com/konnov/apalache diff --git a/docs/spec/tendermint-fork-cases/counterexample-vc0-w2.tla b/docs/spec/tendermint-fork-cases/counterexample-vc0-w2.tla new file mode 100644 index 000000000..3f5666bd2 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/counterexample-vc0-w2.tla @@ -0,0 +1,3576 @@ +------------------------- MODULE Counterexample ------------------------- + +\* Transition 0: State 0 to State 1: + +ConstInit == Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "c1" + +\* Transition 0: State 0 to State 1: + +State1 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "c1" + /\ decision = "c1" :> "None" @@ "c2" :> "None" + /\ evidence = {} + /\ lockedRound = "c1" :> -1 @@ "c2" :> -1 + /\ lockedValue = "c1" :> "None" @@ "c2" :> "None" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 0 + /\ step = "c1" :> "PROPOSE" @@ "c2" :> "PROPOSE" + /\ validRound = "c1" :> -1 @@ "c2" :> -1 + /\ validValue = "c1" :> "None" @@ "c2" :> "None" + +\* Transition 0: State 1 to State 2: + +State2 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "c1" + /\ decision = "c1" :> "None" @@ "c2" :> "None" + /\ evidence + = { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ lockedRound = "c1" :> -1 @@ "c2" :> -1 + /\ lockedValue = "c1" :> "None" @@ "c2" :> "None" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 1 + /\ step = "c1" :> "PROPOSE" @@ "c2" :> "PROPOSE" + /\ validRound = "c1" :> -1 @@ "c2" :> -1 + /\ validValue = "c1" :> "None" @@ "c2" :> "None" + +\* Transition 9: State 2 to State 3: + +State3 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "c1" + /\ decision = "c1" :> "None" @@ "c2" :> "None" + /\ evidence + = {[proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1]} + /\ lockedRound = "c1" :> -1 @@ "c2" :> -1 + /\ lockedValue = "c1" :> "None" @@ "c2" :> "None" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 1 + /\ step = "c1" :> "PREVOTE" @@ "c2" :> "PROPOSE" + /\ validRound = "c1" :> -1 @@ "c2" :> -1 + /\ validValue = "c1" :> "None" @@ "c2" :> "None" + +\* Transition 5: State 3 to State 4: + +State4 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "c1" + /\ decision = "c1" :> "None" @@ "c2" :> "None" + /\ evidence + = { [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ lockedRound = "c1" :> 0 @@ "c2" :> -1 + /\ lockedValue = "c1" :> "v1" @@ "c2" :> "None" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 1 + /\ step = "c1" :> "PRECOMMIT" @@ "c2" :> "PROPOSE" + /\ validRound = "c1" :> 0 @@ "c2" :> -1 + /\ validValue = "c1" :> "v1" @@ "c2" :> "None" + +\* Transition 0: State 4 to State 5: + +State5 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "c1" + /\ decision = "c1" :> "None" @@ "c2" :> "None" + /\ evidence + = {[proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1]} + /\ lockedRound = "c1" :> 0 @@ "c2" :> -1 + /\ lockedValue = "c1" :> "v1" @@ "c2" :> "None" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 1 + /\ step = "c1" :> "PRECOMMIT" @@ "c2" :> "PREVOTE" + /\ validRound = "c1" :> 0 @@ "c2" :> -1 + /\ validValue = "c1" :> "v1" @@ "c2" :> "None" + +\* Transition 5: State 5 to State 6: + +State6 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "c1" + /\ decision = "c1" :> "None" @@ "c2" :> "None" + /\ evidence + = { [id |-> "v0", round |-> 1, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1] } + /\ lockedRound = "c1" :> 0 @@ "c2" :> 1 + /\ lockedValue = "c1" :> "v1" @@ "c2" :> "v0" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 1 + /\ step = "c1" :> "PRECOMMIT" @@ "c2" :> "PRECOMMIT" + /\ validRound = "c1" :> 0 @@ "c2" :> 1 + /\ validValue = "c1" :> "v1" @@ "c2" :> "v0" + +\* Transition 0: State 6 to State 7: + +State7 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "c1" + /\ decision = "c1" :> "None" @@ "c2" :> "v0" + /\ evidence + = { [id |-> "v0", round |-> 1, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ lockedRound = "c1" :> 0 @@ "c2" :> 1 + /\ lockedValue = "c1" :> "v1" @@ "c2" :> "v0" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 1 + /\ step = "c1" :> "PRECOMMIT" @@ "c2" :> "DECIDED" + /\ validRound = "c1" :> 0 @@ "c2" :> 1 + /\ validValue = "c1" :> "v1" @@ "c2" :> "v0" + +\* Transition 7: State 7 to State 8: + +State8 == + Proposer = 0 :> "f3" @@ 1 :> "f3" @@ 2 :> "c1" + /\ decision = "c1" :> "v1" @@ "c2" :> "v0" + /\ evidence + = { [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0] } + /\ lockedRound = "c1" :> 0 @@ "c2" :> 1 + /\ lockedValue = "c1" :> "v1" @@ "c2" :> "v0" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 1 + /\ step = "c1" :> "DECIDED" @@ "c2" :> "DECIDED" + /\ validRound = "c1" :> 0 @@ "c2" :> 1 + /\ validValue = "c1" :> "v1" @@ "c2" :> "v0" + +(* The following formula holds true in State8 and violates the invariant *) +InvariantViolation == + BMC!Skolem((\E p$20 \in { "c1", "c2" }: + BMC!Skolem((\E q$2 \in { "c1", "c2" }: + ~(decision[p$20] = "None") + /\ ~(decision[q$2] = "None") + /\ ~(decision[p$20] = decision[q$2]))))) +================================================================================ +\* Created Tue Mar 10 18:20:30 CET 2020 by Apalache +\* https://github.com/konnov/apalache diff --git a/docs/spec/tendermint-fork-cases/counterexample-vc0-w3.tla b/docs/spec/tendermint-fork-cases/counterexample-vc0-w3.tla new file mode 100644 index 000000000..73761957b --- /dev/null +++ b/docs/spec/tendermint-fork-cases/counterexample-vc0-w3.tla @@ -0,0 +1,3023 @@ +------------------------- MODULE Counterexample ------------------------- + +\* Transition 0: State 0 to State 1: + +ConstInit == Proposer = 0 :> "f3" @@ 1 :> "c1" @@ 2 :> "f4" + +\* Transition 0: State 0 to State 1: + +State1 == + Proposer = 0 :> "f3" @@ 1 :> "c1" @@ 2 :> "f4" + /\ decision = "c1" :> "None" @@ "c2" :> "None" + /\ evidence = {} + /\ lockedRound = "c1" :> -1 @@ "c2" :> -1 + /\ lockedValue = "c1" :> "None" @@ "c2" :> "None" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 0 + /\ step = "c1" :> "PROPOSE" @@ "c2" :> "PROPOSE" + /\ validRound = "c1" :> -1 @@ "c2" :> -1 + /\ validValue = "c1" :> "None" @@ "c2" :> "None" + +\* Transition 0: State 1 to State 2: + +State2 == + Proposer = 0 :> "f3" @@ 1 :> "c1" @@ 2 :> "f4" + /\ decision = "c1" :> "None" @@ "c2" :> "None" + /\ evidence + = {[proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1]} + /\ lockedRound = "c1" :> -1 @@ "c2" :> -1 + /\ lockedValue = "c1" :> "None" @@ "c2" :> "None" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 0 + /\ step = "c1" :> "PROPOSE" @@ "c2" :> "PREVOTE" + /\ validRound = "c1" :> -1 @@ "c2" :> -1 + /\ validValue = "c1" :> "None" @@ "c2" :> "None" + +\* Transition 9: State 2 to State 3: + +State3 == + Proposer = 0 :> "f3" @@ 1 :> "c1" @@ 2 :> "f4" + /\ decision = "c1" :> "None" @@ "c2" :> "None" + /\ evidence + = { [id |-> "v0", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1] } + /\ lockedRound = "c1" :> -1 @@ "c2" :> 0 + /\ lockedValue = "c1" :> "None" @@ "c2" :> "v0" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 0 + /\ step = "c1" :> "PROPOSE" @@ "c2" :> "PRECOMMIT" + /\ validRound = "c1" :> -1 @@ "c2" :> 0 + /\ validValue = "c1" :> "None" @@ "c2" :> "v0" + +\* Transition 2: State 3 to State 4: + +State4 == + Proposer = 0 :> "f3" @@ 1 :> "c1" @@ 2 :> "f4" + /\ decision = "c1" :> "None" @@ "c2" :> "None" + /\ evidence + = {[proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1]} + /\ lockedRound = "c1" :> -1 @@ "c2" :> 0 + /\ lockedValue = "c1" :> "None" @@ "c2" :> "v0" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 0 + /\ step = "c1" :> "PREVOTE" @@ "c2" :> "PRECOMMIT" + /\ validRound = "c1" :> -1 @@ "c2" :> 0 + /\ validValue = "c1" :> "None" @@ "c2" :> "v0" + +\* Transition 9: State 4 to State 5: + +State5 == + Proposer = 0 :> "f3" @@ 1 :> "c1" @@ 2 :> "f4" + /\ decision = "c1" :> "None" @@ "c2" :> "None" + /\ evidence + = { [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1] } + /\ lockedRound = "c1" :> 0 @@ "c2" :> 0 + /\ lockedValue = "c1" :> "v1" @@ "c2" :> "v0" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 0 + /\ step = "c1" :> "PRECOMMIT" @@ "c2" :> "PRECOMMIT" + /\ validRound = "c1" :> 0 @@ "c2" :> 0 + /\ validValue = "c1" :> "v1" @@ "c2" :> "v0" + +\* Transition 2: State 5 to State 6: + +State6 == + Proposer = 0 :> "f3" @@ 1 :> "c1" @@ 2 :> "f4" + /\ decision = "c1" :> "v1" @@ "c2" :> "None" + /\ evidence + = { [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0] } + /\ lockedRound = "c1" :> 0 @@ "c2" :> 0 + /\ lockedValue = "c1" :> "v1" @@ "c2" :> "v0" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 0 + /\ step = "c1" :> "DECIDED" @@ "c2" :> "PRECOMMIT" + /\ validRound = "c1" :> 0 @@ "c2" :> 0 + /\ validValue = "c1" :> "v1" @@ "c2" :> "v0" + +\* Transition 8: State 6 to State 7: + +State7 == + Proposer = 0 :> "f3" @@ 1 :> "c1" @@ 2 :> "f4" + /\ decision = "c1" :> "v1" @@ "c2" :> "v0" + /\ evidence + = { [id |-> "v0", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0] } + /\ lockedRound = "c1" :> 0 @@ "c2" :> 0 + /\ lockedValue = "c1" :> "v1" @@ "c2" :> "v0" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 @@ "c2" :> 0 + /\ step = "c1" :> "DECIDED" @@ "c2" :> "DECIDED" + /\ validRound = "c1" :> 0 @@ "c2" :> 0 + /\ validValue = "c1" :> "v1" @@ "c2" :> "v0" + +(* The following formula holds true in State7 and violates the invariant *) +InvariantViolation == + BMC!Skolem((\E p$20 \in { "c1", "c2" }: + BMC!Skolem((\E q$2 \in { "c1", "c2" }: + ~(decision[p$20] = "None") + /\ ~(decision[q$2] = "None") + /\ ~(decision[p$20] = decision[q$2]))))) +================================================================================ +\* Created Sat Mar 28 17:41:29 CET 2020 by Apalache +\* https://github.com/konnov/apalache diff --git a/docs/spec/tendermint-fork-cases/counterexample-vc31-w1.tla b/docs/spec/tendermint-fork-cases/counterexample-vc31-w1.tla new file mode 100644 index 000000000..8331cac17 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/counterexample-vc31-w1.tla @@ -0,0 +1,651 @@ +------------------------- MODULE Counterexample ------------------------- + +\* Transition 0: State 0 to State 1: + +ConstInit == Proposer = 0 :> "a3" @@ 1 :> "f4" @@ 2 :> "c1" + +\* Transition 0: State 0 to State 1: + +State1 == + Proposer = 0 :> "a3" @@ 1 :> "f4" @@ 2 :> "c1" + /\ decision = "c1" :> "None" + /\ evidence = {} + /\ lockedRound = "c1" :> -1 + /\ lockedValue = "c1" :> "None" + /\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "a2", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "a3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "a2", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "a3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "a2", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "a3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "a2", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "a3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "a2", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "a3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "a2", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "a3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "a2", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "a3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "a2", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "a3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "a2", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "a3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } + /\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "a2", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "a3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "a2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "a3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "a2", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "a3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "a2", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "a3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "a2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "a3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "a2", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "a3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "a2", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "a3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "a2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "a3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "a2", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "a3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } + /\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "a2", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "a3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + /\ round = "c1" :> 0 + /\ step = "c1" :> "PROPOSE" + /\ validRound = "c1" :> -1 + /\ validValue = "c1" :> "None" + +(* The following formula holds true in State1 and violates the invariant *) +InvariantViolation == + BMC!Skolem((\E r$40 \in 0 .. 2: + BMC!Skolem((\E v$14 \in { "v0", "v1" } \union {"None"}: + LET t_66 == + { + m$53["src"]: + m$53 \in { m$54 \in msgsPrecommit[r$40]: m$54["id"] = v$14 } + } + IN + BMC!Skolem((\E t_64 \in t_66: + BMC!Skolem((\E t_65 \in t_66: ~(t_64 = t_65))))) + /\ BMC!Skolem((\E rr$13 \in 0 .. 2: + rr$13 > r$40 + /\ BMC!Skolem((\E t_60$1 \in ({ "v0", "v1" } \union {"v2"}) + \union {"None"}: + ~(t_60$1 \in {v$14}) + /\ BMC!ConstCardinality((Cardinality({ + m$55["src"]: + m$55 \in + { m$56 \in msgsPrevote[rr$13]: m$56["id"] = t_60$1 } + }) + >= 3)))))))))) +================================================================================ +\* Created Sat Mar 21 11:30:17 CET 2020 by Apalache +\* https://github.com/konnov/apalache diff --git a/docs/spec/tendermint-fork-cases/counterexample.tla b/docs/spec/tendermint-fork-cases/counterexample.tla new file mode 100644 index 000000000..88a0367f1 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/counterexample.tla @@ -0,0 +1,3028 @@ +------------------------- MODULE counterexample ------------------------- + +EXTENDS MC_n4_f2 + +(* Initial state *) + +State1 == +/\ Proposer = 0 :> "f4" @@ 1 :> "c2" @@ 2 :> "c1" + +(* Transition 0 to State2 *) + +State2 == +/\ Proposer = 0 :> "f4" @@ 1 :> "c2" @@ 2 :> "c1" +/\ decision = "c1" :> "None" @@ "c2" :> "None" +/\ evidence = {} +/\ lockedRound = "c1" :> -1 @@ "c2" :> -1 +/\ lockedValue = "c1" :> "None" @@ "c2" :> "None" +/\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } +/\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } +/\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } +/\ round = "c1" :> 0 @@ "c2" :> 0 +/\ step = "c1" :> "PROPOSE" @@ "c2" :> "PROPOSE" +/\ validRound = "c1" :> -1 @@ "c2" :> -1 +/\ validValue = "c1" :> "None" @@ "c2" :> "None" + +(* Transition 1 to State3 *) + +State3 == +/\ Proposer = 0 :> "f4" @@ 1 :> "c2" @@ 2 :> "c1" +/\ decision = "c1" :> "None" @@ "c2" :> "None" +/\ evidence + = {[proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1]} +/\ lockedRound = "c1" :> -1 @@ "c2" :> -1 +/\ lockedValue = "c1" :> "None" @@ "c2" :> "None" +/\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } +/\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } +/\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } +/\ round = "c1" :> 0 @@ "c2" :> 0 +/\ step = "c1" :> "PREVOTE" @@ "c2" :> "PROPOSE" +/\ validRound = "c1" :> -1 @@ "c2" :> -1 +/\ validValue = "c1" :> "None" @@ "c2" :> "None" + +(* Transition 5 to State4 *) + +State4 == +/\ Proposer = 0 :> "f4" @@ 1 :> "c2" @@ 2 :> "c1" +/\ decision = "c1" :> "None" @@ "c2" :> "None" +/\ evidence + = { [id |-> "v0", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0] } +/\ lockedRound = "c1" :> 0 @@ "c2" :> -1 +/\ lockedValue = "c1" :> "v0" @@ "c2" :> "None" +/\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } +/\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } +/\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } +/\ round = "c1" :> 0 @@ "c2" :> 0 +/\ step = "c1" :> "PRECOMMIT" @@ "c2" :> "PROPOSE" +/\ validRound = "c1" :> 0 @@ "c2" :> -1 +/\ validValue = "c1" :> "v0" @@ "c2" :> "None" + +(* Transition 2 to State5 *) + +State5 == +/\ Proposer = 0 :> "f4" @@ 1 :> "c2" @@ 2 :> "c1" +/\ decision = "c1" :> "None" @@ "c2" :> "None" +/\ evidence + = {[proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1]} +/\ lockedRound = "c1" :> 0 @@ "c2" :> -1 +/\ lockedValue = "c1" :> "v0" @@ "c2" :> "None" +/\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } +/\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } +/\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } +/\ round = "c1" :> 0 @@ "c2" :> 0 +/\ step = "c1" :> "PRECOMMIT" @@ "c2" :> "PREVOTE" +/\ validRound = "c1" :> 0 @@ "c2" :> -1 +/\ validValue = "c1" :> "v0" @@ "c2" :> "None" + +(* Transition 7 to State6 *) + +State6 == +/\ Proposer = 0 :> "f4" @@ 1 :> "c2" @@ 2 :> "c1" +/\ decision = "c1" :> "None" @@ "c2" :> "None" +/\ evidence + = { [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0] } +/\ lockedRound = "c1" :> 0 @@ "c2" :> 0 +/\ lockedValue = "c1" :> "v0" @@ "c2" :> "v1" +/\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } +/\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } +/\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } +/\ round = "c1" :> 0 @@ "c2" :> 0 +/\ step = "c1" :> "PRECOMMIT" @@ "c2" :> "PRECOMMIT" +/\ validRound = "c1" :> 0 @@ "c2" :> 0 +/\ validValue = "c1" :> "v0" @@ "c2" :> "v1" + +(* Transition 8 to State7 *) + +State7 == +/\ Proposer = 0 :> "f4" @@ 1 :> "c2" @@ 2 :> "c1" +/\ decision = "c1" :> "v1" @@ "c2" :> "None" +/\ evidence + = { [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0] } +/\ lockedRound = "c1" :> 0 @@ "c2" :> 0 +/\ lockedValue = "c1" :> "v0" @@ "c2" :> "v1" +/\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } +/\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } +/\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } +/\ round = "c1" :> 0 @@ "c2" :> 0 +/\ step = "c1" :> "DECIDED" @@ "c2" :> "PRECOMMIT" +/\ validRound = "c1" :> 0 @@ "c2" :> 0 +/\ validValue = "c1" :> "v0" @@ "c2" :> "v1" + +(* Transition 9 to State8 *) + +State8 == +/\ Proposer = 0 :> "f4" @@ 1 :> "c2" @@ 2 :> "c1" +/\ decision = "c1" :> "v1" @@ "c2" :> "v0" +/\ evidence + = { [id |-> "v0", round |-> 0, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0] } +/\ lockedRound = "c1" :> 0 @@ "c2" :> 0 +/\ lockedValue = "c1" :> "v0" @@ "c2" :> "v1" +/\ msgsPrecommit + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c1", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PRECOMMIT"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PRECOMMIT"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PRECOMMIT"] } +/\ msgsPrevote + = 0 + :> { [id |-> "v0", round |-> 0, src |-> "c1", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "c2", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 0, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 0, src |-> "f4", type |-> "PREVOTE"] } + @@ 1 + :> { [id |-> "v0", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 1, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 1, src |-> "f4", type |-> "PREVOTE"] } + @@ 2 + :> { [id |-> "v0", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v0", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v1", round |-> 2, src |-> "f4", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f3", type |-> "PREVOTE"], + [id |-> "v2", round |-> 2, src |-> "f4", type |-> "PREVOTE"] } +/\ msgsPropose + = 0 + :> { [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 0, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 1 + :> { [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 1, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } + @@ 2 + :> { [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v0", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v1", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f3", + type |-> "PROPOSAL", + validRound |-> 2], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> -1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 0], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 1], + [proposal |-> "v2", + round |-> 2, + src |-> "f4", + type |-> "PROPOSAL", + validRound |-> 2] } +/\ round = "c1" :> 0 @@ "c2" :> 0 +/\ step = "c1" :> "DECIDED" @@ "c2" :> "DECIDED" +/\ validRound = "c1" :> 0 @@ "c2" :> 0 +/\ validValue = "c1" :> "v0" @@ "c2" :> "v1" + +(* The following formula holds true in the last state and violates the invariant *) + +InvariantViolation == + BMC!Skolem((\E p$20 \in { "c1", "c2" }: + BMC!Skolem((\E q$2 \in { "c1", "c2" }: + ~(decision[p$20] = "None") + /\ ~(decision[q$2] = "None") + /\ ~(decision[p$20] = decision[q$2]))))) + +================================================================================ +\* Created by Apalache on Sat Mar 28 16:57:25 CET 2020 +\* https://github.com/konnov/apalache diff --git a/docs/spec/tendermint-fork-cases/run.sh b/docs/spec/tendermint-fork-cases/run.sh new file mode 100755 index 000000000..929d7ba91 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/run.sh @@ -0,0 +1,9 @@ +#!/bin/sh +# +# The script to run all experiments at once + +export SCRIPTS_DIR=~/devl/apalache-tests/scripts +export BUILDS="unstable card" +export BENCHMARK=001indinv-apalache +export RUN_SCRIPT=./run-all.sh # alternatively, use ./run-parallel.sh +make -e -f ~/devl/apalache-tests/Makefile.common diff --git a/docs/spec/tendermint-fork/Tendermint.tla b/docs/spec/tendermint-fork/Tendermint.tla deleted file mode 100644 index 461d2e06f..000000000 --- a/docs/spec/tendermint-fork/Tendermint.tla +++ /dev/null @@ -1,374 +0,0 @@ ------------------------------ MODULE Tendermint ----------------------------- -(* - A TLA+ specification of Tendermint consensus by Ethan Buchman, Jae Kwon, and Zarko Milosevic. - - For the moment, we assume the following: - - 1. Every process has the voting power of 1. - 2. Timeouts are non-deterministic (works for safety). - 3. The proposer function is non-deterministic (works for safety). - - Encoded in TLA+ by Igor Konnov. It took me 4 hours to translate the pseudo-code to TLA+. - *) - -EXTENDS Integers, FiniteSets - -CONSTANTS - PropFun, \* the proposer function - Injected \* a set of the messages injected by the faulty processes - -N == 5 \* the total number of processes: correct and faulty -T == 1 \* an upper bound on the number of Byzantine processes -F == 1 \* the number of Byzantine processes -Procs == 1..N-F -Faulty == N-F+1..N -Heights == 0..1 \* the set of consensus instances -Rounds == 0..2 \* the set of possible rounds, give a bit more freedom to the solver -ValidValues == {0, 1} \* e.g., picked by a correct process, or a faulty one -InvalidValues == {2} \* e.g., sent by a Byzantine process -Values == ValidValues \cup InvalidValues \* all values -nil == -1 - -\* these are two tresholds that are used in the algorithm -THRESHOLD1 == T + 1 -THRESHOLD2 == 2 * T + 1 - -(* APALACHE-BEGIN annotations *) -a <: b == a - -MT == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, - proposal |-> Int, validRound |-> Int, hash |-> Int] -ET == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, value |-> Int] \* processed events, "for the first time" - -ValueT == Int -RoundT == Int -TimeoutT == <> \* process, height, round -(* APALACHE-END *) - -FaultyMessages == \* the messages that can be sent by the faulty processes - ([type: {"PROPOSAL"}, src: Faulty, h: Heights, - round: Rounds, proposal: Values, validRound: Rounds \cup {-1}] <: {MT}) - \cup - ([type: {"PREVOTE"}, src: Faulty, h: Heights, round: Rounds, hash: Values] <: {MT}) - \cup - ([type: {"PRECOMMIT"}, src: Faulty, h: Heights, round: Rounds, hash: Values] <: {MT}) - -NInjected == 1 \* the number of injected faulty messages -ConstInit == - /\ PropFun \in [Heights \X Rounds -> Procs] - /\ Injected \in [1..NInjected -> FaultyMessages] - - -\* these variables are exactly as in the pseudo-code -VARIABLES h, round, step, decision, lockedValue, lockedRound, validValue, validRound - -\* book-keeping variables -VARIABLES msgsPropose, \* the propose messages broadcasted in the system, a function Heights \X Rounds -> set of messages - msgsPrevote, \* the prevote messages broadcasted in the system, a function Heights \X Rounds -> set of messages - msgsPrecommit, \* the precommit messages broadcasted in the system, a function Heights \X Rounds -> set of messages - oldEvents, \* the messages processed once, as expressed by "for the first time" - timeoutPropose, \* a set of proposed timeouts: <> - timeoutPrevote, \* a set of proposed timeouts: <> - timeoutPrecommit \* a set of proposed timeouts: <> - -\* this is needed for UNCHANGED -vars == <> - -\* A function which gives the proposer for a given round at a given height. -\* Here we use round robin. As Procs and Faulty are assigned non-deterministically, -\* it does not really matter who starts first. -Proposer(ht, rd) == PropFun[ht, rd] \*1 + ((ht + rd) % N) - -Id(v) == v - -IsValid(v) == v \in ValidValues - -MixinFaults(ht, rd, type, msgs) == - \* add the messages from the faulty processes, filtered by height, round, and type - msgs \cup {m \in {Injected[x] : x \in 1..NInjected} : m.h = ht /\ m.round = rd /\ m.type = type} - -\* here we start with StartRound(0) -Init == - /\ h = [p \in Procs |-> 0] - /\ round = [p \in Procs |-> 0] - /\ step = [p \in Procs |-> "PROPOSE"] - /\ decision = [p \in Procs |-> [ht \in Heights |-> nil]] - /\ lockedValue = [p \in Procs |-> nil] - /\ lockedRound = [p \in Procs |-> -1] - /\ validValue = [p \in Procs |-> nil] - /\ validRound = [p \in Procs |-> -1] - /\ \E v \in ValidValues: - msgsPropose = [<> \in Heights \X Rounds |-> - MixinFaults(ht, rd, "PROPOSAL", - IF ht = 0 /\ rd = 0 - THEN {[type |-> "PROPOSAL", src |-> Proposer(0, 0), h |-> 0, round |-> 0, - proposal |-> v, validRound |-> -1] <: MT} - ELSE {} <: {MT})] \* no initial messages in other rounds - /\ msgsPrevote = [<> \in Heights \X Rounds |-> MixinFaults(ht, rd, "PREVOTE", {} <: {MT})] - /\ msgsPrecommit = [<> \in Heights \X Rounds |-> MixinFaults(ht, rd, "PRECOMMIT", {} <: {MT})] - /\ oldEvents = {} <: {ET} - /\ timeoutPropose = { <> : p \in Procs \ {Proposer(0, 0)}} - /\ timeoutPrevote = {} <: {TimeoutT} \* no PREVOTE timeouts - /\ timeoutPrecommit = {} <: {TimeoutT} \* no PRECOMMIT timeouts - -\* lines 22-27 -UponProposalInPropose(p) == - \E v \in Values: - /\ step[p] = "PROPOSE" \* line 22 - /\ ([type |-> "PROPOSAL", src |-> Proposer(h[p], round[p]), h |-> h[p], - round |-> round[p], proposal |-> v, validRound |-> -1] <: MT) \in msgsPropose[h[p], round[p]] \* line 22 - /\ LET isGood == IsValid(v) /\ (lockedRound[p] = -1 \/ lockedValue[p] = v) IN \* line 23 - LET newMsgs == ({[type |-> "PREVOTE", src |-> p, h |-> h[p], - round |-> round[p], hash |-> IF isGood THEN Id(v) ELSE nil] <: MT}) - IN \* lines 24-26 - msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = - msgsPrevote[h[p], round[p]] \cup newMsgs] - /\ step' = [step EXCEPT ![p] = "PREVOTE"] - /\ UNCHANGED <> - -\* lines 28-33 -UponProposalInProposeAndPrevote(p) == - \E v \in Values, vr \in Rounds: - /\ step[p] = "PROPOSE" /\ 0 <= vr /\ vr < round[p] \* line 28, the while part - /\ ([type |-> "PROPOSAL", src |-> Proposer(h[p], round[p]), h |-> h[p], - round |-> round[p], proposal |-> v, validRound |-> vr] <: MT) \in msgsPropose[h[p], round[p]] \* line 28 - /\ LET PV == { m \in msgsPrevote[h[p], vr]: m.hash = Id(v) } IN - Cardinality(PV) >= THRESHOLD2 \* line 28 - /\ LET isGood == IsValid(v) /\ (lockedRound[p] <= vr \/ lockedValue[p] = v) IN \* line 29 - LET newMsgs == ({[type |-> "PREVOTE", src |-> p, h |-> h[p], - round |-> round[p], hash |-> IF isGood THEN Id(v) ELSE nil] <: MT}) - IN \* lines 30-32 - msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = - msgsPrevote[h[p], round[p]] \cup newMsgs] - /\ step' = [step EXCEPT ![p] = "PREVOTE"] - /\ UNCHANGED <> - -\* lines 34-35 -UponPrevoteFirstTime(p) == - /\ step[p] = "PREVOTE" \* line 34 - /\ Cardinality(msgsPrevote[h[p], round[p]]) >= THRESHOLD2 \* line 34 - /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], round |-> round[p], value |-> nil] IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* process it only once - /\ timeoutPrevote' = timeoutPrevote \cup {<>} \* line 35 - /\ UNCHANGED <> - -\* lines 36-46 -UponProposalInPrevoteOrCommitAndPrevote(p) == - \E v \in ValidValues, vr \in Rounds \cup {-1}: - /\ step[p] \in {"PREVOTE", "PRECOMMIT"} \* line 36 - /\ ([type |-> "PROPOSAL", src |-> Proposer(h[p], round[p]), h |-> h[p], - round |-> round[p], proposal |-> v, validRound |-> vr] <: MT) \in msgsPropose[h[p], round[p]] \* line 36 - /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], round |-> round[p], value |-> Id(v)] IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* record that it should not happen again - /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = Id(v) } IN - Cardinality(PV) >= THRESHOLD2 \* line 36 - /\ lockedValue' = - IF step[p] = "PREVOTE" - THEN [lockedValue EXCEPT ![p] = v] \* line 38 - ELSE lockedValue \* else of line 37 - /\ lockedRound' = - IF step[p] = "PREVOTE" - THEN [lockedRound EXCEPT ![p] = round[p]] \* line 39 - ELSE lockedRound \* else of line 37 - /\ LET newMsgs == - IF step[p] = "PREVOTE" - THEN {[type |-> "PRECOMMIT", src |-> p, h |-> h[p], round |-> round[p], hash |-> Id(v)] <: MT} \* line 40 - ELSE {} <: {MT} - IN \* else of line 37 - msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = - msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 40, or else of 37 - /\ step' = IF step[p] = "PREVOTE" THEN [step EXCEPT ![p] = "PRECOMMIT"] ELSE step \* line 41 - /\ validValue' = [validValue EXCEPT ![p] = v] \* line 42 - /\ validRound' = [validRound EXCEPT ![p] = round[p]] \* line 43 - /\ UNCHANGED <> - -\* Apparently, this action is needed to deal with a value proposed by a Byzantine process -\* This action is particularly hard for the model checker -\* lines 44-46 -UponPrevoteNil(p) == - /\ step[p] = "PREVOTE" \* line 44 - /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = nil } IN - Cardinality(PV) >= THRESHOLD2 \* line 34 - /\ step' = [step EXCEPT ![p] = "PRECOMMIT"] - /\ LET newMsgs == ({[type |-> "PRECOMMIT", src |-> p, h |-> h[p], - round |-> round[p], hash |-> nil] <: MT}) \* line 45 - IN - msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = - msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 45 - /\ UNCHANGED <> - -\* lines 47-48 -UponPrecommitFirstTime(p) == - /\ Cardinality(msgsPrecommit[h[p], round[p]]) >= THRESHOLD2 \* line 47 - /\ LET event == [type |-> "PRECOMMIT", src |-> p, h |-> h[p], round |-> round[p], value |-> nil] IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* process it only once - /\ timeoutPrecommit' = timeoutPrecommit \cup {<>} \* line 48 - /\ UNCHANGED <> - -\* lines 11-21 -StartRound(p, ht, r) == - /\ round' = [round EXCEPT ![p] = r] - /\ step' = [step EXCEPT ![p] = "PROPOSE"] - /\ \E v \in ValidValues: \* lines 14-21 - LET proposal == IF validValue[p] /= nil THEN validValue[p] ELSE v IN - LET newMsgs == - IF p = Proposer(ht, r) - THEN {[type |-> "PROPOSAL", src |-> p, h |-> ht, round |-> r, - proposal |-> proposal, validRound |-> validRound[p]] <: MT} - ELSE {} <: {MT} - IN - msgsPropose' = [msgsPropose EXCEPT ![ht, r] = - msgsPropose[ht, r] \cup newMsgs] \* line 19 - /\ LET newTimeouts == \* line 21 - IF p = Proposer(ht, r) - THEN {} <: {TimeoutT} \* no new timeouts - ELSE { <> } - IN - timeoutPropose' = timeoutPropose \cup newTimeouts - -\* lines 49-54 -UponProposalInPrecommitNoDecision(p) == - /\ h[p] + 1 \in Heights - \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, - \* BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING - /\ decision[p][h[p]] = nil \* line 49 - /\ \E v \in ValidValues (* line 50*) , r \in Rounds, vr \in Rounds \cup {-1}: - /\ ([type |-> "PROPOSAL", src |-> Proposer(h[p], r), h |-> h[p], - round |-> r, proposal |-> v, validRound |-> vr] <: MT) \in msgsPropose[h[p], r] \* line 49 - /\ LET PV == { m \in msgsPrecommit[h[p], r]: m.hash = Id(v) } IN - Cardinality(PV) >= THRESHOLD2 \* line 49 - /\ decision' = [decision EXCEPT ![p][h[p]] = v] \* update the decision, line 51 - /\ h' = [h EXCEPT ![p] = h[p] + 1] \* line 52 - \* line 53 - /\ lockedRound' = [lockedRound EXCEPT ![p] = -1] - /\ lockedValue' = [lockedValue EXCEPT ![p] = nil] - /\ validRound' = [validRound EXCEPT ![p] = -1] - /\ validValue' = [validValue EXCEPT ![p] = nil] - \* What does it mean to reset the message buffer? Do it for one process only? - /\ StartRound(p, h[p] + 1, 0) - /\ UNCHANGED <> - -\* lines 55-56 -UponCatchupRound(p) == - \E r \in Rounds: - /\ r > round[p] - /\ LET PV == msgsPropose[h[p], r] \cup msgsPrevote[h[p], r] \cup msgsPrecommit[h[p], r] IN - Cardinality(PV) >= THRESHOLD1 \* line 55 - /\ StartRound(p, h[p], r) - /\ UNCHANGED <> - -\* lines 57-60 -OnTimeoutPropose(p) == - \E tm \in timeoutPropose: \* a timeout occurs - /\ tm[1] = p - /\ timeoutPropose' = timeoutPropose \ {tm} \* remove from the future timeouts - /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PROPOSE" IN - /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PREVOTE"] ELSE step \* line 60 - /\ LET newMsgs == - IF UpdateNeeded - THEN {[type |-> "PREVOTE", src |-> tm[1], h |-> tm[2], round |-> tm[3], hash |-> nil] <: MT} \* line 59 - ELSE {} <: {MT} \* else of line 58 - IN \* line 59, or else of 58 - msgsPrevote' = [msgsPrevote EXCEPT ![tm[2], tm[3]] = - msgsPrevote[tm[2], tm[3]] \cup newMsgs] - /\ UNCHANGED <> - -\* lines 61-64 -OnTimeoutPrevote(p) == - \E tm \in timeoutPrevote: \* a timeout occurs - /\ tm[1] = p - /\ timeoutPrevote' = timeoutPrevote \ {tm} \* remove from the future timeouts - /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PREVOTE" IN - /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PRECOMMIT"] ELSE step \* line 64 - /\ LET newMsgs == - IF UpdateNeeded - THEN {[type |-> "PRECOMMIT", src |-> tm[1], h |-> tm[2], round |-> tm[3], hash |-> nil] <: MT} \* line 63 - ELSE {} <: {MT} \* else of line 62 - IN \* line 63, or else of 62 - msgsPrecommit' = [msgsPrecommit EXCEPT ![tm[2], tm[3]] = - msgsPrecommit[tm[2], tm[3]] \cup newMsgs] - /\ UNCHANGED <> - -\* lines 65-67 -OnTimeoutPrecommitOutside(p) == - \E tm \in timeoutPrecommit: \* a timeout occurs - /\ tm[1] = p - /\ (tm[2] /= h[p] \/ tm[3] /= round[p]) \* but we are in another round or height - /\ timeoutPrecommit' = timeoutPrecommit \ {tm} \* remove from the future timeouts - /\ UNCHANGED <> - -\* lines 65-67 -OnTimeoutPrecommitInside(p) == - /\ round[p] + 1 \in Rounds - \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, - \* BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING - /\ <> \in timeoutPrecommit \* the timeout occurs for the current round and height - /\ timeoutPrecommit' = timeoutPrecommit \ {<>} \* remove from the future timeouts - /\ StartRound(p, h[p], round[p] + 1) - /\ UNCHANGED <> - - -Next == - \/ \E p \in Procs: - \/ UponProposalInPropose(p) - \/ UponProposalInProposeAndPrevote(p) - \/ UponPrevoteFirstTime(p) - \/ UponProposalInPrevoteOrCommitAndPrevote(p) - \/ UponPrevoteNil(p) - \/ UponPrecommitFirstTime(p) - \/ UponProposalInPrecommitNoDecision(p) - \/ UponCatchupRound(p) - \/ OnTimeoutPropose(p) - \/ OnTimeoutPrevote(p) - \/ OnTimeoutPrecommitOutside(p) - \/ OnTimeoutPrecommitInside(p) - \* a safeguard to prevent deadlocks when the algorithm goes to further heights or rounds - \*\/ UNCHANGED vars - -\* safety -Agreement == - \A p, q \in Procs, ht \in Heights: - decision[p][ht] = nil \/ decision[q][ht] = nil \/ decision[p][ht] = decision[q][ht] - -\* simple reachability properties to make sure that the algorithm is doing anything useful -NoDecision == \A p \in Procs, ht \in Heights: decision[p][ht] = nil - -NoPrecommit == \A p \in Procs: step[p] /= "PRECOMMIT" - -NoTwoLockedValues == - \A p, q \in Procs: - h[p] = h[q] => lockedValue[p] = nil \/ lockedValue[q] = nil \/ lockedValue[p] = lockedValue[q] - -NoTwoLockedRounds == - \A p, q \in Procs: - h[p] = h[q] => lockedRound[p] = -1 \/ lockedRound[q] = -1 \/ lockedRound[p] = lockedRound[q] - - -============================================================================= -\* Modification History -\* Last modified Mon Sep 16 15:00:22 CEST 2019 by igor -\* Created Fri Mar 15 10:30:17 CET 2019 by igor diff --git a/docs/spec/tendermint-fork/Tendermint3.tla b/docs/spec/tendermint-fork/Tendermint3.tla deleted file mode 100644 index ea88283d1..000000000 --- a/docs/spec/tendermint-fork/Tendermint3.tla +++ /dev/null @@ -1,376 +0,0 @@ ------------------------------ MODULE Tendermint3 ----------------------------- -(* - A TLA+ specification of Tendermint consensus by Ethan Buchman, Jae Kwon, and Zarko Milosevic. - - For the moment, we assume the following: - - 1. Every process has the voting power of 1. - 2. Timeouts are non-deterministic (works for safety). - 3. The proposer function is non-deterministic (works for safety). - - Encoded in TLA+ by Igor Konnov. It took me 4 hours to translate the pseudo-code to TLA+. - - Version 3: assuming that f = 1, - using AtLeast2(S) and AtLeast3(s) instead of - Cardinality(S) >= f + 1 and Cardinality(S) >= 2f + 1 - *) - -EXTENDS Integers, FiniteSets - -CONSTANTS - PropFun, \* the proposer function - Injected \* a set of the messages injected by the faulty processes - -N == 4 \* the total number of processes: correct and faulty -T == 1 \* an upper bound on the number of Byzantine processes -F == 0 \* the number of Byzantine processes -Procs == 1..N-F -Faulty == N-F+1..N -Heights == 0..1 \* the set of consensus instances -Rounds == 0..2 \* the set of possible rounds, give a bit more freedom to the solver -ValidValues == {0, 1} \* e.g., picked by a correct process, or a faulty one -InvalidValues == {2} \* e.g., sent by a Byzantine process -Values == ValidValues \cup InvalidValues \* all values -nil == -1 - -\* these are two tresholds that are used in the algorithm -THRESHOLD1 == T + 1 -THRESHOLD2 == 2 * T + 1 - -(* APALACHE-BEGIN annotations *) -a <: b == a - -MT == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, - proposal |-> Int, validRound |-> Int, hash |-> Int] -ET == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, value |-> Int] \* processed events, "for the first time" - -\* this is an optimization, in order to avoid cardinality constraints -AtLeast2(S) == \E x, y \in S: x /= y -AtLeast3(S) == \E x, y, z \in S: x /= y /\ x /= z /\ y /= z - -ValueT == Int -RoundT == Int -TimeoutT == <> \* process, height, round -(* APALACHE-END *) - -FaultyMessages == \* the messages that can be sent by the faulty processes - ([type: {"PROPOSAL"}, src: Faulty, h: Heights, - round: Rounds, proposal: Values, validRound: Rounds \cup {-1}] <: {MT}) - \cup - ([type: {"PREVOTE"}, src: Faulty, h: Heights, round: Rounds, hash: Values] <: {MT}) - \cup - ([type: {"PRECOMMIT"}, src: Faulty, h: Heights, round: Rounds, hash: Values] <: {MT}) - -NInjected == 0 \* the number of injected faulty messages -ConstInit == - /\ PropFun \in [Heights \X Rounds -> Procs] - /\ Injected \in [1..NInjected -> FaultyMessages] - - -\* these variables are exactly as in the pseudo-code -VARIABLES h, round, step, decision, lockedValue, lockedRound, validValue, validRound - -\* book-keeping variables -VARIABLES msgsPropose, \* the propose messages broadcasted in the system, a function Heights \X Rounds -> set of messages - msgsPrevote, \* the prevote messages broadcasted in the system, a function Heights \X Rounds -> set of messages - msgsPrecommit, \* the precommit messages broadcasted in the system, a function Heights \X Rounds -> set of messages - oldEvents, \* the messages processed once, as expressed by "for the first time" - timeoutPropose, \* a set of proposed timeouts: <> - timeoutPrevote, \* a set of proposed timeouts: <> - timeoutPrecommit \* a set of proposed timeouts: <> - -\* this is needed for UNCHANGED -vars == <> - -\* A function which gives the proposer for a given round at a given height. -\* Here we use round robin. As Procs and Faulty are assigned non-deterministically, -\* it does not really matter who starts first. -Proposer(ht, rd) == PropFun[ht, rd] \*1 + ((ht + rd) % N) - -Id(v) == v - -IsValid(v) == v \in ValidValues - -MixinFaults(ht, rd, type, msgs) == - \* add the messages from the faulty processes, filtered by height, round, and type - msgs \cup {m \in {Injected[x] : x \in 1..NInjected} : m.h = ht /\ m.round = rd /\ m.type = type} - -\* here we start with StartRound(0) -Init == - /\ h = [p \in Procs |-> 0] - /\ round = [p \in Procs |-> 0] - /\ step = [p \in Procs |-> "PROPOSE"] - /\ decision = [p \in Procs |-> [ht \in Heights |-> nil]] - /\ lockedValue = [p \in Procs |-> nil] - /\ lockedRound = [p \in Procs |-> -1] - /\ validValue = [p \in Procs |-> nil] - /\ validRound = [p \in Procs |-> -1] - /\ \E v \in ValidValues: - msgsPropose = [<> \in Heights \X Rounds |-> - MixinFaults(ht, rd, "PROPOSAL", - IF ht = 0 /\ rd = 0 - THEN {[type |-> "PROPOSAL", src |-> Proposer(0, 0), h |-> 0, round |-> 0, proposal |-> v, validRound |-> -1] <: MT} - ELSE {} <: {MT})] \* no initial messages in other rounds - /\ msgsPrevote = [<> \in Heights \X Rounds |-> MixinFaults(ht, rd, "PREVOTE", {} <: {MT})] - /\ msgsPrecommit = [<> \in Heights \X Rounds |-> MixinFaults(ht, rd, "PRECOMMIT", {} <: {MT})] - /\ oldEvents = {} <: {ET} - /\ timeoutPropose = { <> : p \in Procs \ {Proposer(0, 0)}} - /\ timeoutPrevote = {} <: {TimeoutT} \* no PREVOTE timeouts - /\ timeoutPrecommit = {} <: {TimeoutT} \* no PRECOMMIT timeouts - -\* lines 22-27 -UponProposalInPropose(p) == - \E v \in Values: - /\ step[p] = "PROPOSE" \* line 22 - /\ ([type |-> "PROPOSAL", src |-> Proposer(h[p], round[p]), h |-> h[p], - round |-> round[p], proposal |-> v, validRound |-> -1] <: MT) \in msgsPropose[h[p], round[p]] \* line 22 - /\ LET isGood == IsValid(v) /\ (lockedRound[p] = -1 \/ lockedValue[p] = v) IN \* line 23 - LET newMsgs == ({[type |-> "PREVOTE", src |-> p, h |-> h[p], - round |-> round[p], hash |-> IF isGood THEN Id(v) ELSE nil] <: MT}) - IN \* lines 24-26 - msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = - msgsPrevote[h[p], round[p]] \cup newMsgs] - /\ step' = [step EXCEPT ![p] = "PREVOTE"] - /\ UNCHANGED <> - -\* lines 28-33 -UponProposalInProposeAndPrevote(p) == - \E v \in Values, vr \in Rounds: - /\ step[p] = "PROPOSE" /\ 0 <= vr /\ vr < round[p] \* line 28, the while part - /\ ([type |-> "PROPOSAL", src |-> Proposer(h[p], round[p]), h |-> h[p], - round |-> round[p], proposal |-> v, validRound |-> vr] <: MT) \in msgsPropose[h[p], round[p]] \* line 28 - /\ LET PV == { m \in msgsPrevote[h[p], vr]: m.hash = Id(v) } IN - AtLeast3(PV) \* line 28 - /\ LET isGood == IsValid(v) /\ (lockedRound[p] <= vr \/ lockedValue[p] = v) IN \* line 29 - LET newMsgs == ({[type |-> "PREVOTE", src |-> p, h |-> h[p], - round |-> round[p], hash |-> IF isGood THEN Id(v) ELSE nil] <: MT}) - IN \* lines 30-32 - msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = - msgsPrevote[h[p], round[p]] \cup newMsgs] - /\ step' = [step EXCEPT ![p] = "PREVOTE"] - /\ UNCHANGED <> - -\* lines 34-35 -UponPrevoteFirstTime(p) == - /\ step[p] = "PREVOTE" \* line 34 - /\ AtLeast3(msgsPrevote[h[p], round[p]]) \* line 34 - /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], round |-> round[p], value |-> nil] IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* process it only once - /\ timeoutPrevote' = timeoutPrevote \cup {<>} \* line 35 - /\ UNCHANGED <> - -\* lines 36-46 -UponProposalInPrevoteOrCommitAndPrevote(p) == - \E v \in ValidValues, vr \in Rounds \cup {-1}: - /\ step[p] \in {"PREVOTE", "PRECOMMIT"} \* line 36 - /\ ([type |-> "PROPOSAL", src |-> Proposer(h[p], round[p]), h |-> h[p], - round |-> round[p], proposal |-> v, validRound |-> vr] <: MT) \in msgsPropose[h[p], round[p]] \* line 36 - /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], round |-> round[p], value |-> Id(v)] IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* record that it should not happen again - /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = Id(v) } IN - AtLeast3(PV) \* line 36 - /\ lockedValue' = - IF step[p] = "PREVOTE" - THEN [lockedValue EXCEPT ![p] = v] \* line 38 - ELSE lockedValue \* else of line 37 - /\ lockedRound' = - IF step[p] = "PREVOTE" - THEN [lockedRound EXCEPT ![p] = round[p]] \* line 39 - ELSE lockedRound \* else of line 37 - /\ LET newMsgs == - IF step[p] = "PREVOTE" - THEN {[type |-> "PRECOMMIT", src |-> p, h |-> h[p], round |-> round[p], hash |-> Id(v)] <: MT} \* line 40 - ELSE {} <: {MT} - IN \* else of line 37 - msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = - msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 40, or else of 37 - /\ step' = IF step[p] = "PREVOTE" THEN [step EXCEPT ![p] = "PRECOMMIT"] ELSE step \* line 41 - /\ validValue' = [validValue EXCEPT ![p] = v] \* line 42 - /\ validRound' = [validRound EXCEPT ![p] = round[p]] \* line 43 - /\ UNCHANGED <> - -\* Apparently, this action is needed to deal with a value proposed by a Byzantine process -\* lines 44-46 -UponPrevoteNil(p) == - /\ step[p] = "PREVOTE" \* line 44 - /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = nil } IN - AtLeast3(PV) \* line 34 - /\ step' = [step EXCEPT ![p] = "PRECOMMIT"] - /\ LET newMsgs == ({[type |-> "PRECOMMIT", src |-> p, h |-> h[p], - round |-> round[p], hash |-> nil] <: MT}) \* line 45 - IN - msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = - msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 45 - /\ UNCHANGED <> - -\* lines 47-48 -UponPrecommitFirstTime(p) == - /\ AtLeast3(msgsPrecommit[h[p], round[p]]) \* line 47 - /\ LET event == [type |-> "PRECOMMIT", src |-> p, h |-> h[p], round |-> round[p], value |-> nil] IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* process it only once - /\ timeoutPrecommit' = timeoutPrecommit \cup {<>} \* line 48 - /\ UNCHANGED <> - -\* lines 11-21 -StartRound(p, ht, r) == - /\ round' = [round EXCEPT ![p] = r] - /\ step' = [step EXCEPT ![p] = "PROPOSE"] - /\ \E v \in ValidValues: \* lines 14-21 - LET proposal == IF validValue[p] /= nil THEN validValue[p] ELSE v IN - LET newMsgs == - IF p = Proposer(ht, r) - THEN {[type |-> "PROPOSAL", src |-> p, h |-> ht, round |-> r, - proposal |-> proposal, validRound |-> validRound[p]] <: MT} - ELSE {} <: {MT} - IN - msgsPropose' = [msgsPropose EXCEPT ![ht, r] = - msgsPropose[ht, r] \cup newMsgs] \* line 19 - /\ LET newTimeouts == \* line 21 - IF p = Proposer(ht, r) - THEN {} <: {TimeoutT} \* no new timeouts - ELSE { <> } - IN - timeoutPropose' = timeoutPropose \cup newTimeouts - -\* lines 49-54 -UponProposalInPrecommitNoDecision(p) == - /\ h[p] + 1 \in Heights - \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING - /\ decision[p][h[p]] = nil \* line 49 - /\ \E v \in ValidValues (* line 50*) , r \in Rounds, vr \in Rounds \cup {-1}: - /\ ([type |-> "PROPOSAL", src |-> Proposer(h[p], r), h |-> h[p], - round |-> r, proposal |-> v, validRound |-> vr] <: MT) \in msgsPropose[h[p], r] \* line 49 - /\ LET PV == { m \in msgsPrecommit[h[p], r]: m.hash = Id(v) } IN - AtLeast3(PV) \* line 49 - /\ decision' = [decision EXCEPT ![p][h[p]] = v] \* update the decision, line 51 - /\ h' = [h EXCEPT ![p] = h[p] + 1] \* line 52 - \* line 53 - /\ lockedRound' = [lockedRound EXCEPT ![p] = -1] - /\ lockedValue' = [lockedValue EXCEPT ![p] = nil] - /\ validRound' = [validRound EXCEPT ![p] = -1] - /\ validValue' = [validValue EXCEPT ![p] = nil] - \* What does it mean to reset the message buffer? Do it for one process only? - /\ StartRound(p, h[p] + 1, 0) - /\ UNCHANGED <> - -\* lines 55-56 -UponCatchupRound(p) == - \E r \in Rounds: - /\ r > round[p] - /\ LET PV == msgsPropose[h[p], r] \cup msgsPrevote[h[p], r] \cup msgsPrecommit[h[p], r] IN - AtLeast2(PV) \* line 55 - /\ StartRound(p, h[p], r) - /\ UNCHANGED <> - -\* lines 57-60 -OnTimeoutPropose(p) == - \E tm \in timeoutPropose: \* a timeout occurs - /\ tm[1] = p - /\ timeoutPropose' = timeoutPropose \ {tm} \* remove from the future timeouts - /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PROPOSE" IN - /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PREVOTE"] ELSE step \* line 60 - /\ LET newMsgs == - IF UpdateNeeded - THEN {[type |-> "PREVOTE", src |-> tm[1], h |-> tm[2], round |-> tm[3], hash |-> nil] <: MT} \* line 59 - ELSE {} <: {MT} \* else of line 58 - IN \* line 59, or else of 58 - msgsPrevote' = [msgsPrevote EXCEPT ![tm[2], tm[3]] = - msgsPrevote[tm[2], tm[3]] \cup newMsgs] - /\ UNCHANGED <> - -\* lines 61-64 -OnTimeoutPrevote(p) == - \E tm \in timeoutPrevote: \* a timeout occurs - /\ tm[1] = p - /\ timeoutPrevote' = timeoutPrevote \ {tm} \* remove from the future timeouts - /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PREVOTE" IN - /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PRECOMMIT"] ELSE step \* line 64 - /\ LET newMsgs == - IF UpdateNeeded - THEN {[type |-> "PRECOMMIT", src |-> tm[1], h |-> tm[2], round |-> tm[3], hash |-> nil] <: MT} \* line 63 - ELSE {} <: {MT} \* else of line 62 - IN \* line 63, or else of 62 - msgsPrecommit' = [msgsPrecommit EXCEPT ![tm[2], tm[3]] = - msgsPrecommit[tm[2], tm[3]] \cup newMsgs] - /\ UNCHANGED <> - -\* lines 65-67 -OnTimeoutPrecommitOutside(p) == - \E tm \in timeoutPrecommit: \* a timeout occurs - /\ tm[1] = p - /\ (tm[2] /= h[p] \/ tm[3] /= round[p]) \* but we are in another round or height - /\ timeoutPrecommit' = timeoutPrecommit \ {tm} \* remove from the future timeouts - /\ UNCHANGED <> - -\* lines 65-67 -OnTimeoutPrecommitInside(p) == - /\ round[p] + 1 \in Rounds - \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING - /\ <> \in timeoutPrecommit \* the timeout occurs for the current round and height - /\ timeoutPrecommit' = timeoutPrecommit \ {<>} \* remove from the future timeouts - /\ StartRound(p, h[p], round[p] + 1) - /\ UNCHANGED <> - - -Next == - \/ \E p \in Procs: - \/ UponProposalInPropose(p) - \/ UponProposalInProposeAndPrevote(p) - \/ UponPrevoteFirstTime(p) - \/ UponProposalInPrevoteOrCommitAndPrevote(p) - \/ UponPrevoteNil(p) \* FIXME: disabled for model checking - \/ UponPrecommitFirstTime(p) - \/ UponProposalInPrecommitNoDecision(p) - \/ UponCatchupRound(p) - \/ OnTimeoutPropose(p) - \/ OnTimeoutPrevote(p) - \/ OnTimeoutPrecommitOutside(p) - \/ OnTimeoutPrecommitInside(p) - \* a safeguard to prevent deadlocks when the algorithm goes to further heights or rounds - \*\/ UNCHANGED vars - -\* safety -Agreement == - \A p, q \in Procs, ht \in Heights: - decision[p][ht] = nil \/ decision[q][ht] = nil \/ decision[p][ht] = decision[q][ht] - -\* simple reachability properties to make sure that the algorithm is doing anything useful -NoDecision == \A p \in Procs, ht \in Heights: decision[p][ht] = nil - -NoPrecommit == \A p \in Procs: step[p] /= "PRECOMMIT" - -NoTwoLockedValues == - \A p, q \in Procs: - h[p] = h[q] => lockedValue[p] = nil \/ lockedValue[q] = nil \/ lockedValue[p] = lockedValue[q] - -NoTwoLockedRounds == - \A p, q \in Procs: - h[p] = h[q] => lockedRound[p] = -1 \/ lockedRound[q] = -1 \/ lockedRound[p] = lockedRound[q] - - -============================================================================= -\* Modification History -\* Last modified Fri Mar 22 08:57:10 CET 2019 by igor -\* Created Fri Mar 15 10:30:17 CET 2019 by igor diff --git a/docs/spec/tendermint-fork/Tendermint4.tla b/docs/spec/tendermint-fork/Tendermint4.tla deleted file mode 100644 index 87b03207a..000000000 --- a/docs/spec/tendermint-fork/Tendermint4.tla +++ /dev/null @@ -1,392 +0,0 @@ ------------------------------ MODULE Tendermint4 ----------------------------- -(* - A TLA+ specification by Igor Konnov - of Tendermint consensus by Ethan Buchman, Jae Kwon, and Zarko Milosevic. - - For the moment, we assume the following: - - 1. Every process has the voting power of 1 (this seems to be complete). - 2. Timeouts are non-deterministic (works for safety). - 3. The proposer function is completely non-deterministic (works for safety). - - It took me 4 hours to translate the pseudo-code to TLA+. - Then it took me several days to make it more efficient for the model checker. - - Version 3: assuming that f = 1, - using AtLeastT1(S) and AtLeastT2(s) instead of - Cardinality(S) >= f + 1 and Cardinality(S) >= 2f + 1 - - Version 4: simplified record types, as we are using separate variables - for different message types and different indices for heights and rounds. - Injecting all Byzantine messages in the initial states. - *) - -EXTENDS Integers, FiniteSets - -CONSTANTS PropFun \* the proposer function - -N == 5 \* the total number of processes: correct and faulty -T == 1 \* an upper bound on the number of Byzantine processes -F == 1 \* the number of Byzantine processes -Procs == 1..N-F -Faulty == N-F+1..N -Heights == 0..1 \* the set of consensus instances -Rounds == 0..2 \* the set of possible rounds, give a bit more freedom to the solver -ValidValues == {0, 1} \* e.g., picked by a correct process, or a faulty one -InvalidValues == {2} \* e.g., sent by a Byzantine process -Values == ValidValues \cup InvalidValues \* all values -nil == -1 - -\* these are two tresholds that are used in the algorithm -THRESHOLD1 == T + 1 -THRESHOLD2 == 2 * T + 1 - -(* APALACHE-BEGIN annotations *) -a <: b == a - -MT == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, - proposal |-> Int, validRound |-> Int, hash |-> Int] -ProposalT == [src |-> Int, proposal |-> Int, validRound |-> Int] -PrevoteT == [src |-> Int, hash |-> Int] -PrecommitT == PrevoteT -ET == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, value |-> Int] \* processed events, "for the first time" - -\* This is an optimization, in order to avoid cardinality constraints -\* If T is different from 1, use the general operators: -\*AtLeastT1(S) == Cardinality(S) >= THRESHOLD1 -\*AtLeastT2(S) == Cardinality(S) >= THRESHOLD2 -AtLeastT1(S) == \E x, y \in S: x /= y -AtLeastT2(S) == \E x, y, z \in S: x /= y /\ x /= z /\ y /= z - -ValueT == Int -RoundT == Int -TimeoutT == <> \* process, height, round -(* APALACHE-END *) - -FaultyProposals == - [src: Faulty, proposal: Values, validRound: Rounds \cup {-1}] - -FaultyPrevotes == [src: Faulty, hash: Values] - -FaultyPrecommits == [src: Faulty, hash: Values] - -ConstInit == PropFun \in [Heights \X Rounds -> Procs] - - -\* these variables are exactly as in the pseudo-code -VARIABLES h, round, step, decision, lockedValue, lockedRound, validValue, validRound - -\* book-keeping variables -VARIABLES msgsPropose, \* the propose messages broadcasted in the system, a function Heights \X Rounds -> set of messages - msgsPrevote, \* the prevote messages broadcasted in the system, a function Heights \X Rounds -> set of messages - msgsPrecommit, \* the precommit messages broadcasted in the system, a function Heights \X Rounds -> set of messages - oldEvents, \* the messages processed once, as expressed by "for the first time" - timeoutPropose, \* a set of proposed timeouts: <> - timeoutPrevote, \* a set of proposed timeouts: <> - timeoutPrecommit \* a set of proposed timeouts: <> - -\* this is needed for UNCHANGED -vars == <> - -\* A function which gives the proposer for a given round at a given height. -\* Here we use round robin. As Procs and Faulty are assigned non-deterministically, -\* it does not really matter who starts first. -Proposer(ht, rd) == PropFun[ht, rd] \*1 + ((ht + rd) % N) - -Id(v) == v - -IsValid(v) == v \in ValidValues - -\* here we start with StartRound(0) -Init == - /\ h = [p \in Procs |-> 0] - /\ round = [p \in Procs |-> 0] - /\ step = [p \in Procs |-> "PROPOSE"] - /\ decision = [p \in Procs |-> [ht \in Heights |-> nil]] - /\ lockedValue = [p \in Procs |-> nil] - /\ lockedRound = [p \in Procs |-> -1] - /\ validValue = [p \in Procs |-> nil] - /\ validRound = [p \in Procs |-> -1] - /\ \E v \in Values: - /\ msgsPropose = - [<> \in Heights \X Rounds |-> - IF ht = 0 /\ rd = 0 - THEN {[src |-> Proposer(0, 0), - proposal |-> v, validRound |-> -1]} \cup FaultyProposals - ELSE FaultyProposals \* only faulty messages - ] - /\ msgsPrevote = [<> \in Heights \X Rounds |-> FaultyPrevotes] - /\ msgsPrecommit = [<> \in Heights \X Rounds |-> FaultyPrecommits] - /\ oldEvents = {} <: {ET} - /\ timeoutPropose = { <> : p \in Procs \ {Proposer(0, 0)}} - /\ timeoutPrevote = {} <: {TimeoutT} \* no PREVOTE timeouts - /\ timeoutPrecommit = {} <: {TimeoutT} \* no PRECOMMIT timeouts - -\* lines 22-27 -UponProposalInPropose(p) == - \E v \in Values: - /\ step[p] = "PROPOSE" \* line 22 - /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> -1] - \in msgsPropose[h[p], round[p]] \* line 22 - /\ LET isGood == IsValid(v) /\ (lockedRound[p] = -1 \/ lockedValue[p] = v) IN \* line 23 - LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} - IN \* lines 24-26 - msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = - msgsPrevote[h[p], round[p]] \cup newMsgs] - /\ step' = [step EXCEPT ![p] = "PREVOTE"] - /\ UNCHANGED <> - -\* lines 28-33 -UponProposalInProposeAndPrevote(p) == - \E v \in Values, vr \in Rounds: - /\ step[p] = "PROPOSE" /\ 0 <= vr /\ vr < round[p] \* line 28, the while part - /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] - \in msgsPropose[h[p], round[p]] \* line 28 - /\ LET PV == { m \in msgsPrevote[h[p], vr]: m.hash = Id(v) } IN - AtLeastT2(PV) \* line 28 - /\ LET isGood == IsValid(v) /\ (lockedRound[p] <= vr \/ lockedValue[p] = v) IN \* line 29 - LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} - IN \* lines 30-32 - msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = - msgsPrevote[h[p], round[p]] \cup newMsgs] - /\ step' = [step EXCEPT ![p] = "PREVOTE"] - /\ UNCHANGED <> - -\* lines 34-35 -UponPrevoteFirstTime(p) == - /\ step[p] = "PREVOTE" \* line 34 - /\ AtLeastT2(msgsPrevote[h[p], round[p]]) \* line 34 - /\ LET event == [type |-> "PREVOTE", src |-> p, - h |-> h[p], round |-> round[p], value |-> nil] - IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* process it only once - /\ timeoutPrevote' = timeoutPrevote \cup {<>} \* line 35 - /\ UNCHANGED <> - -\* lines 36-46 -UponProposalInPrevoteOrCommitAndPrevote(p) == - \E v \in ValidValues, vr \in Rounds \cup {-1}: - /\ step[p] \in {"PREVOTE", "PRECOMMIT"} \* line 36 - /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] - \in msgsPropose[h[p], round[p]] \* line 36 - /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], - round |-> round[p], value |-> Id(v)] IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* record that it should not happen again - /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = Id(v) } IN - AtLeastT2(PV) \* line 36 - /\ lockedValue' = - IF step[p] = "PREVOTE" - THEN [lockedValue EXCEPT ![p] = v] \* line 38 - ELSE lockedValue \* else of line 37 - /\ lockedRound' = - IF step[p] = "PREVOTE" - THEN [lockedRound EXCEPT ![p] = round[p]] \* line 39 - ELSE lockedRound \* else of line 37 - /\ LET newMsgs == - IF step[p] = "PREVOTE" - THEN {[src |-> p, hash |-> Id(v)]} \* line 40 - ELSE {} <: {PrecommitT} - IN \* else of line 37 - msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = - msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 40, or else of 37 - /\ step' = - IF step[p] = "PREVOTE" - THEN [step EXCEPT ![p] = "PRECOMMIT"] - ELSE step \* line 41 - /\ validValue' = [validValue EXCEPT ![p] = v] \* line 42 - /\ validRound' = [validRound EXCEPT ![p] = round[p]] \* line 43 - /\ UNCHANGED <> - -\* Apparently, this action is needed to deal with a value proposed by a Byzantine process -\* lines 44-46 -UponPrevoteNil(p) == - /\ step[p] = "PREVOTE" \* line 44 - /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = nil } - IN - AtLeastT2(PV) \* line 34 - /\ step' = [step EXCEPT ![p] = "PRECOMMIT"] - /\ LET newMsgs == {[src |-> p, hash |-> nil]} \* line 45 - IN - msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = - msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 45 - /\ UNCHANGED <> - -\* lines 47-48 -UponPrecommitFirstTime(p) == - /\ AtLeastT2(msgsPrecommit[h[p], round[p]]) \* line 47 - /\ LET event == [type |-> "PRECOMMIT", src |-> p, - h |-> h[p], round |-> round[p], value |-> nil] - IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* process it only once - /\ timeoutPrecommit' = timeoutPrecommit \cup {<>} \* line 48 - /\ UNCHANGED <> - -\* lines 11-21 -StartRound(p, ht, r) == - /\ round' = [round EXCEPT ![p] = r] - /\ step' = [step EXCEPT ![p] = "PROPOSE"] - /\ \E v \in ValidValues: \* lines 14-21 - LET proposal == IF validValue[p] /= nil THEN validValue[p] ELSE v IN - LET newMsgs == - IF p = Proposer(ht, r) - THEN {[src |-> p, proposal |-> proposal, validRound |-> validRound[p]]} - ELSE {} <: {ProposalT} - IN - msgsPropose' = [msgsPropose EXCEPT ![ht, r] = - msgsPropose[ht, r] \cup newMsgs] \* line 19 - /\ LET newTimeouts == \* line 21 - IF p = Proposer(ht, r) - THEN {} <: {TimeoutT} \* no new timeouts - ELSE { <> } - IN - timeoutPropose' = timeoutPropose \cup newTimeouts - -\* lines 49-54 -UponProposalInPrecommitNoDecision(p) == - /\ h[p] + 1 \in Heights - \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING - /\ decision[p][h[p]] = nil \* line 49 - /\ \E v \in ValidValues (* line 50*) , r \in Rounds, vr \in Rounds \cup {-1}: - /\ [src |-> Proposer(h[p], r), proposal |-> v, validRound |-> vr] - \in msgsPropose[h[p], r] \* line 49 - /\ LET PV == { m \in msgsPrecommit[h[p], r]: m.hash = Id(v) } IN - AtLeastT2(PV) \* line 49 - /\ decision' = [decision EXCEPT ![p][h[p]] = v] \* update the decision, line 51 - /\ h' = [h EXCEPT ![p] = h[p] + 1] \* line 52 - \* line 53 - /\ lockedRound' = [lockedRound EXCEPT ![p] = -1] - /\ lockedValue' = [lockedValue EXCEPT ![p] = nil] - /\ validRound' = [validRound EXCEPT ![p] = -1] - /\ validValue' = [validValue EXCEPT ![p] = nil] - \* What does it mean to reset the message buffer? Do it for one process only? - /\ StartRound(p, h[p] + 1, 0) - /\ UNCHANGED <> - -\* lines 55-56 -UponCatchupRound(p) == - \E r \in Rounds: - /\ r > round[p] - /\ LET ps == { m.src : m \in msgsPropose[h[p], r]} IN - LET pv == { m.src : m \in msgsPrevote[h[p], r]} IN - LET pc == { m.src : m \in msgsPrecommit[h[p], r]} IN - AtLeastT1(ps \cup pv \cup pc) \* line 55 - /\ StartRound(p, h[p], r) - /\ UNCHANGED <> - -\* lines 57-60 -OnTimeoutPropose(p) == - \E tm \in timeoutPropose: \* a timeout occurs - /\ tm[1] = p - /\ timeoutPropose' = timeoutPropose \ {tm} \* remove from the future timeouts - /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PROPOSE" IN - /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PREVOTE"] ELSE step \* line 60 - /\ LET newMsgs == - IF UpdateNeeded - THEN {[src |-> tm[1], hash |-> nil]} \* line 59 - ELSE {} <: {PrevoteT} \* else of line 58 - IN \* line 59, or else of 58 - msgsPrevote' = [msgsPrevote EXCEPT ![tm[2], tm[3]] = - msgsPrevote[tm[2], tm[3]] \cup newMsgs] - /\ UNCHANGED <> - -\* lines 61-64 -OnTimeoutPrevote(p) == - \E tm \in timeoutPrevote: \* a timeout occurs - /\ tm[1] = p - /\ timeoutPrevote' = timeoutPrevote \ {tm} \* remove from the future timeouts - /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PREVOTE" IN - /\ step' = - IF UpdateNeeded - THEN [step EXCEPT ![p] = "PRECOMMIT"] - ELSE step \* line 64 - /\ LET newMsgs == - IF UpdateNeeded - THEN {[src |-> tm[1], hash |-> nil]} \* line 63 - ELSE {} <: {PrecommitT} \* else of line 62 - IN \* line 63, or else of 62 - msgsPrecommit' = [msgsPrecommit EXCEPT ![tm[2], tm[3]] = - msgsPrecommit[tm[2], tm[3]] \cup newMsgs] - /\ UNCHANGED <> - -\* lines 65-67 -OnTimeoutPrecommitOutside(p) == - \E tm \in timeoutPrecommit: \* a timeout occurs - /\ tm[1] = p - /\ (tm[2] /= h[p] \/ tm[3] /= round[p]) \* but we are in another round or height - /\ timeoutPrecommit' = timeoutPrecommit \ {tm} \* remove from the future timeouts - /\ UNCHANGED <> - -\* lines 65-67 -OnTimeoutPrecommitInside(p) == - /\ round[p] + 1 \in Rounds - \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING - /\ <> \in timeoutPrecommit \* the timeout occurs for the current round and height - /\ timeoutPrecommit' = timeoutPrecommit \ {<>} \* remove from the future timeouts - /\ StartRound(p, h[p], round[p] + 1) - /\ UNCHANGED <> - - -Next == - \/ \E p \in Procs: - \/ UponProposalInPropose(p) - \/ UponProposalInProposeAndPrevote(p) - \/ UponPrevoteFirstTime(p) - \/ UponProposalInPrevoteOrCommitAndPrevote(p) - \/ UponPrevoteNil(p) \* FIXME: disabled for model checking - \/ UponPrecommitFirstTime(p) - \/ UponProposalInPrecommitNoDecision(p) - \/ UponCatchupRound(p) - \/ OnTimeoutPropose(p) - \/ OnTimeoutPrevote(p) - \/ OnTimeoutPrecommitOutside(p) - \/ OnTimeoutPrecommitInside(p) - \* a safeguard to prevent deadlocks when the algorithm goes to further heights or rounds - \*\/ UNCHANGED vars - -\* safety -Agreement == - \A p, q \in Procs, ht \in Heights: - \/ decision[p][ht] = nil - \/ decision[q][ht] = nil - \/ decision[p][ht] = decision[q][ht] - -\* simple reachability properties to make sure that the algorithm is doing anything useful -NoDecision == \A p \in Procs, ht \in Heights: decision[p][ht] = nil - -NoPrecommit == \A p \in Procs: step[p] /= "PRECOMMIT" - -NoTwoLockedValues == - \A p, q \in Procs: - h[p] = h[q] => lockedValue[p] = nil \/ lockedValue[q] = nil \/ lockedValue[p] = lockedValue[q] - -NoTwoLockedRounds == - \A p, q \in Procs: - h[p] = h[q] => lockedRound[p] = -1 \/ lockedRound[q] = -1 \/ lockedRound[p] = lockedRound[q] - - -============================================================================= -\* Modification History -\* Last modified Fri Mar 22 08:57:10 CET 2019 by igor -\* Created Fri Mar 15 10:30:17 CET 2019 by igor diff --git a/docs/spec/tendermint-fork/Tendermint4n4f0.tla b/docs/spec/tendermint-fork/Tendermint4n4f0.tla deleted file mode 100644 index fdd7169a7..000000000 --- a/docs/spec/tendermint-fork/Tendermint4n4f0.tla +++ /dev/null @@ -1,387 +0,0 @@ ------------------------------ MODULE Tendermint4n4f0 -------------------- -(* - A TLA+ specification of Tendermint consensus by Ethan Buchman, Jae Kwon, and Zarko Milosevic. - - For the moment, we assume the following: - - 1. Every process has the voting power of 1. - 2. Timeouts are non-deterministic (works for safety). - 3. The proposer function is non-deterministic (works for safety). - - Encoded in TLA+ by Igor Konnov. It took me 4 hours to translate the pseudo-code to TLA+. - - Version 3: assuming that f = 1, - using AtLeastT1(S) and AtLeastT2(s) instead of - Cardinality(S) >= f + 1 and Cardinality(S) >= 2f + 1 - *) - -EXTENDS Integers, FiniteSets - -CONSTANTS PropFun \* the proposer function - -N == 4 \* the total number of processes: correct and faulty -T == 0 \* an upper bound on the number of Byzantine processes -F == 0 \* the number of Byzantine processes -Procs == 1..N-F -Faulty == N-F+1..N -Heights == 0..1 \* the set of consensus instances -Rounds == 0..2 \* the set of possible rounds, give a bit more freedom to the solver -ValidValues == {0, 1} \* e.g., picked by a correct process, or a faulty one -InvalidValues == {2} \* e.g., sent by a Byzantine process -Values == ValidValues \cup InvalidValues \* all values -nil == -1 - -\* these are two tresholds that are used in the algorithm -THRESHOLD1 == T + 1 -THRESHOLD2 == 2 * T + 1 - -(* APALACHE-BEGIN annotations *) -a <: b == a - -MT == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, - proposal |-> Int, validRound |-> Int, hash |-> Int] -ProposalT == [src |-> Int, proposal |-> Int, validRound |-> Int] -PrevoteT == [src |-> Int, hash |-> Int] -PrecommitT == PrevoteT -ET == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, value |-> Int] \* processed events, "for the first time" - -\* this is an optimization, in order to avoid cardinality constraints -\* one faulty process: -\*AtLeastT1(S) == \E x, y \in S: x /= y -\*AtLeastT2(S) == \E x, y, z \in S: x /= y /\ x /= z /\ y /= z -\* no faults: -AtLeastT1(S) == \E x \in S: TRUE -AtLeastT2(S) == \E x, y \in S: x /= y - -ValueT == Int -RoundT == Int -TimeoutT == <> \* process, height, round -(* APALACHE-END *) - -FaultyProposals == - [src: Faulty, proposal: Values, validRound: Rounds \cup {-1}] - -FaultyPrevotes == [src: Faulty, hash: Values] - -FaultyPrecommits == [src: Faulty, hash: Values] - -ConstInit == PropFun \in [Heights \X Rounds -> Procs] - - -\* these variables are exactly as in the pseudo-code -VARIABLES h, round, step, decision, lockedValue, lockedRound, validValue, validRound - -\* book-keeping variables -VARIABLES msgsPropose, \* the propose messages broadcasted in the system, a function Heights \X Rounds -> set of messages - msgsPrevote, \* the prevote messages broadcasted in the system, a function Heights \X Rounds -> set of messages - msgsPrecommit, \* the precommit messages broadcasted in the system, a function Heights \X Rounds -> set of messages - oldEvents, \* the messages processed once, as expressed by "for the first time" - timeoutPropose, \* a set of proposed timeouts: <> - timeoutPrevote, \* a set of proposed timeouts: <> - timeoutPrecommit \* a set of proposed timeouts: <> - -\* this is needed for UNCHANGED -vars == <> - -\* A function which gives the proposer for a given round at a given height. -\* Here we use round robin. As Procs and Faulty are assigned non-deterministically, -\* it does not really matter who starts first. -Proposer(ht, rd) == PropFun[ht, rd] \*1 + ((ht + rd) % N) - -Id(v) == v - -IsValid(v) == v \in ValidValues - -\* here we start with StartRound(0) -Init == - /\ h = [p \in Procs |-> 0] - /\ round = [p \in Procs |-> 0] - /\ step = [p \in Procs |-> "PROPOSE"] - /\ decision = [p \in Procs |-> [ht \in Heights |-> nil]] - /\ lockedValue = [p \in Procs |-> nil] - /\ lockedRound = [p \in Procs |-> -1] - /\ validValue = [p \in Procs |-> nil] - /\ validRound = [p \in Procs |-> -1] - /\ \E v \in Values: - /\ msgsPropose = - [<> \in Heights \X Rounds |-> - IF ht = 0 /\ rd = 0 - THEN {[src |-> Proposer(0, 0), - proposal |-> v, validRound |-> -1]} \cup FaultyProposals - ELSE FaultyProposals \* only faulty messages - ] - /\ msgsPrevote = [<> \in Heights \X Rounds |-> FaultyPrevotes] - /\ msgsPrecommit = [<> \in Heights \X Rounds |-> FaultyPrecommits] - /\ oldEvents = {} <: {ET} - /\ timeoutPropose = { <> : p \in Procs \ {Proposer(0, 0)}} - /\ timeoutPrevote = {} <: {TimeoutT} \* no PREVOTE timeouts - /\ timeoutPrecommit = {} <: {TimeoutT} \* no PRECOMMIT timeouts - -\* lines 22-27 -UponProposalInPropose(p) == - \E v \in Values: - /\ step[p] = "PROPOSE" \* line 22 - /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> -1] - \in msgsPropose[h[p], round[p]] \* line 22 - /\ LET isGood == IsValid(v) /\ (lockedRound[p] = -1 \/ lockedValue[p] = v) IN \* line 23 - LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} - IN \* lines 24-26 - msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = - msgsPrevote[h[p], round[p]] \cup newMsgs] - /\ step' = [step EXCEPT ![p] = "PREVOTE"] - /\ UNCHANGED <> - -\* lines 28-33 -UponProposalInProposeAndPrevote(p) == - \E v \in Values, vr \in Rounds: - /\ step[p] = "PROPOSE" /\ 0 <= vr /\ vr < round[p] \* line 28, the while part - /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] - \in msgsPropose[h[p], round[p]] \* line 28 - /\ LET PV == { m \in msgsPrevote[h[p], vr]: m.hash = Id(v) } IN - AtLeastT2(PV) \* line 28 - /\ LET isGood == IsValid(v) /\ (lockedRound[p] <= vr \/ lockedValue[p] = v) IN \* line 29 - LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} - IN \* lines 30-32 - msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = - msgsPrevote[h[p], round[p]] \cup newMsgs] - /\ step' = [step EXCEPT ![p] = "PREVOTE"] - /\ UNCHANGED <> - -\* lines 34-35 -UponPrevoteFirstTime(p) == - /\ step[p] = "PREVOTE" \* line 34 - /\ AtLeastT2(msgsPrevote[h[p], round[p]]) \* line 34 - /\ LET event == [type |-> "PREVOTE", src |-> p, - h |-> h[p], round |-> round[p], value |-> nil] - IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* process it only once - /\ timeoutPrevote' = timeoutPrevote \cup {<>} \* line 35 - /\ UNCHANGED <> - -\* lines 36-46 -UponProposalInPrevoteOrCommitAndPrevote(p) == - \E v \in ValidValues, vr \in Rounds \cup {-1}: - /\ step[p] \in {"PREVOTE", "PRECOMMIT"} \* line 36 - /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] - \in msgsPropose[h[p], round[p]] \* line 36 - /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], - round |-> round[p], value |-> Id(v)] IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* record that it should not happen again - /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = Id(v) } IN - AtLeastT2(PV) \* line 36 - /\ lockedValue' = - IF step[p] = "PREVOTE" - THEN [lockedValue EXCEPT ![p] = v] \* line 38 - ELSE lockedValue \* else of line 37 - /\ lockedRound' = - IF step[p] = "PREVOTE" - THEN [lockedRound EXCEPT ![p] = round[p]] \* line 39 - ELSE lockedRound \* else of line 37 - /\ LET newMsgs == - IF step[p] = "PREVOTE" - THEN {[src |-> p, hash |-> Id(v)]} \* line 40 - ELSE {} <: {PrecommitT} - IN \* else of line 37 - msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = - msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 40, or else of 37 - /\ step' = - IF step[p] = "PREVOTE" - THEN [step EXCEPT ![p] = "PRECOMMIT"] - ELSE step \* line 41 - /\ validValue' = [validValue EXCEPT ![p] = v] \* line 42 - /\ validRound' = [validRound EXCEPT ![p] = round[p]] \* line 43 - /\ UNCHANGED <> - -\* Apparently, this action is needed to deal with a value proposed by a Byzantine process -\* lines 44-46 -UponPrevoteNil(p) == - /\ step[p] = "PREVOTE" \* line 44 - /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = nil } - IN - AtLeastT2(PV) \* line 34 - /\ step' = [step EXCEPT ![p] = "PRECOMMIT"] - /\ LET newMsgs == {[src |-> p, hash |-> nil]} \* line 45 - IN - msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = - msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 45 - /\ UNCHANGED <> - -\* lines 47-48 -UponPrecommitFirstTime(p) == - /\ AtLeastT2(msgsPrecommit[h[p], round[p]]) \* line 47 - /\ LET event == [type |-> "PRECOMMIT", src |-> p, - h |-> h[p], round |-> round[p], value |-> nil] - IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* process it only once - /\ timeoutPrecommit' = timeoutPrecommit \cup {<>} \* line 48 - /\ UNCHANGED <> - -\* lines 11-21 -StartRound(p, ht, r) == - /\ round' = [round EXCEPT ![p] = r] - /\ step' = [step EXCEPT ![p] = "PROPOSE"] - /\ \E v \in ValidValues: \* lines 14-21 - LET proposal == IF validValue[p] /= nil THEN validValue[p] ELSE v IN - LET newMsgs == - IF p = Proposer(ht, r) - THEN {[src |-> p, proposal |-> proposal, validRound |-> validRound[p]]} - ELSE {} <: {ProposalT} - IN - msgsPropose' = [msgsPropose EXCEPT ![ht, r] = - msgsPropose[ht, r] \cup newMsgs] \* line 19 - /\ LET newTimeouts == \* line 21 - IF p = Proposer(ht, r) - THEN {} <: {TimeoutT} \* no new timeouts - ELSE { <> } - IN - timeoutPropose' = timeoutPropose \cup newTimeouts - -\* lines 49-54 -UponProposalInPrecommitNoDecision(p) == - /\ h[p] + 1 \in Heights - \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING - /\ decision[p][h[p]] = nil \* line 49 - /\ \E v \in ValidValues (* line 50*) , r \in Rounds, vr \in Rounds \cup {-1}: - /\ [src |-> Proposer(h[p], r), proposal |-> v, validRound |-> vr] - \in msgsPropose[h[p], r] \* line 49 - /\ LET PV == { m \in msgsPrecommit[h[p], r]: m.hash = Id(v) } IN - AtLeastT2(PV) \* line 49 - /\ decision' = [decision EXCEPT ![p][h[p]] = v] \* update the decision, line 51 - /\ h' = [h EXCEPT ![p] = h[p] + 1] \* line 52 - \* line 53 - /\ lockedRound' = [lockedRound EXCEPT ![p] = -1] - /\ lockedValue' = [lockedValue EXCEPT ![p] = nil] - /\ validRound' = [validRound EXCEPT ![p] = -1] - /\ validValue' = [validValue EXCEPT ![p] = nil] - \* What does it mean to reset the message buffer? Do it for one process only? - /\ StartRound(p, h[p] + 1, 0) - /\ UNCHANGED <> - -\* lines 55-56 -UponCatchupRound(p) == - \E r \in Rounds: - /\ r > round[p] - /\ LET ps == { m.src : m \in msgsPropose[h[p], r]} IN - LET pv == { m.src : m \in msgsPrevote[h[p], r]} IN - LET pc == { m.src : m \in msgsPrecommit[h[p], r]} IN - AtLeastT1(ps \cup pv \cup pc) \* line 55 - /\ StartRound(p, h[p], r) - /\ UNCHANGED <> - -\* lines 57-60 -OnTimeoutPropose(p) == - \E tm \in timeoutPropose: \* a timeout occurs - /\ tm[1] = p - /\ timeoutPropose' = timeoutPropose \ {tm} \* remove from the future timeouts - /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PROPOSE" IN - /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PREVOTE"] ELSE step \* line 60 - /\ LET newMsgs == - IF UpdateNeeded - THEN {[src |-> tm[1], hash |-> nil]} \* line 59 - ELSE {} <: {PrevoteT} \* else of line 58 - IN \* line 59, or else of 58 - msgsPrevote' = [msgsPrevote EXCEPT ![tm[2], tm[3]] = - msgsPrevote[tm[2], tm[3]] \cup newMsgs] - /\ UNCHANGED <> - -\* lines 61-64 -OnTimeoutPrevote(p) == - \E tm \in timeoutPrevote: \* a timeout occurs - /\ tm[1] = p - /\ timeoutPrevote' = timeoutPrevote \ {tm} \* remove from the future timeouts - /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PREVOTE" IN - /\ step' = - IF UpdateNeeded - THEN [step EXCEPT ![p] = "PRECOMMIT"] - ELSE step \* line 64 - /\ LET newMsgs == - IF UpdateNeeded - THEN {[src |-> tm[1], hash |-> nil]} \* line 63 - ELSE {} <: {PrecommitT} \* else of line 62 - IN \* line 63, or else of 62 - msgsPrecommit' = [msgsPrecommit EXCEPT ![tm[2], tm[3]] = - msgsPrecommit[tm[2], tm[3]] \cup newMsgs] - /\ UNCHANGED <> - -\* lines 65-67 -OnTimeoutPrecommitOutside(p) == - \E tm \in timeoutPrecommit: \* a timeout occurs - /\ tm[1] = p - /\ (tm[2] /= h[p] \/ tm[3] /= round[p]) \* but we are in another round or height - /\ timeoutPrecommit' = timeoutPrecommit \ {tm} \* remove from the future timeouts - /\ UNCHANGED <> - -\* lines 65-67 -OnTimeoutPrecommitInside(p) == - /\ round[p] + 1 \in Rounds - \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING - /\ <> \in timeoutPrecommit \* the timeout occurs for the current round and height - /\ timeoutPrecommit' = timeoutPrecommit \ {<>} \* remove from the future timeouts - /\ StartRound(p, h[p], round[p] + 1) - /\ UNCHANGED <> - - -Next == - \/ \E p \in Procs: - \/ UponProposalInPropose(p) - \/ UponProposalInProposeAndPrevote(p) - \/ UponPrevoteFirstTime(p) - \/ UponProposalInPrevoteOrCommitAndPrevote(p) - \/ UponPrevoteNil(p) \* FIXME: disabled for model checking - \/ UponPrecommitFirstTime(p) - \/ UponProposalInPrecommitNoDecision(p) - \/ UponCatchupRound(p) - \/ OnTimeoutPropose(p) - \/ OnTimeoutPrevote(p) - \/ OnTimeoutPrecommitOutside(p) - \/ OnTimeoutPrecommitInside(p) - \* a safeguard to prevent deadlocks when the algorithm goes to further heights or rounds - \*\/ UNCHANGED vars - -\* safety -Agreement == - \A p, q \in Procs, ht \in Heights: - \/ decision[p][ht] = nil - \/ decision[q][ht] = nil - \/ decision[p][ht] = decision[q][ht] - -\* simple reachability properties to make sure that the algorithm is doing anything useful -NoDecision == \A p \in Procs, ht \in Heights: decision[p][ht] = nil - -NoPrecommit == \A p \in Procs: step[p] /= "PRECOMMIT" - -NoTwoLockedValues == - \A p, q \in Procs: - h[p] = h[q] => lockedValue[p] = nil \/ lockedValue[q] = nil \/ lockedValue[p] = lockedValue[q] - -NoTwoLockedRounds == - \A p, q \in Procs: - h[p] = h[q] => lockedRound[p] = -1 \/ lockedRound[q] = -1 \/ lockedRound[p] = lockedRound[q] - - -============================================================================= -\* Modification History -\* Last modified Fri Mar 22 08:57:10 CET 2019 by igor -\* Created Fri Mar 15 10:30:17 CET 2019 by igor diff --git a/docs/spec/tendermint-fork/Tendermint4n4f1.tla b/docs/spec/tendermint-fork/Tendermint4n4f1.tla deleted file mode 100644 index cc8087ca7..000000000 --- a/docs/spec/tendermint-fork/Tendermint4n4f1.tla +++ /dev/null @@ -1,392 +0,0 @@ ------------------------------ MODULE Tendermint4n4f1 -------------------------- -(* - A TLA+ specification by Igor Konnov - of Tendermint consensus by Ethan Buchman, Jae Kwon, and Zarko Milosevic. - - For the moment, we assume the following: - - 1. Every process has the voting power of 1 (this seems to be complete). - 2. Timeouts are non-deterministic (works for safety). - 3. The proposer function is completely non-deterministic (works for safety). - - It took me 4 hours to translate the pseudo-code to TLA+. - Then it took me several days to make it more efficient for the model checker. - - Version 3: assuming that f = 1, - using AtLeastT1(S) and AtLeastT2(s) instead of - Cardinality(S) >= f + 1 and Cardinality(S) >= 2f + 1 - - Version 4: simplified record types, as we are using separate variables - for different message types and different indices for heights and rounds. - Injecting all Byzantine messages in the initial states. - *) - -EXTENDS Integers, FiniteSets - -CONSTANTS PropFun \* the proposer function - -N == 4 \* the total number of processes: correct and faulty -T == 1 \* an upper bound on the number of Byzantine processes -F == 1 \* the number of Byzantine processes -Procs == 1..N-F -Faulty == N-F+1..N -Heights == 0..1 \* the set of consensus instances -Rounds == 0..2 \* the set of possible rounds, give a bit more freedom to the solver -ValidValues == {0, 1} \* e.g., picked by a correct process, or a faulty one -InvalidValues == {2} \* e.g., sent by a Byzantine process -Values == ValidValues \cup InvalidValues \* all values -nil == -1 - -\* these are two tresholds that are used in the algorithm -THRESHOLD1 == T + 1 -THRESHOLD2 == 2 * T + 1 - -(* APALACHE-BEGIN annotations *) -a <: b == a - -MT == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, - proposal |-> Int, validRound |-> Int, hash |-> Int] -ProposalT == [src |-> Int, proposal |-> Int, validRound |-> Int] -PrevoteT == [src |-> Int, hash |-> Int] -PrecommitT == PrevoteT -ET == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, value |-> Int] \* processed events, "for the first time" - -\* This is an optimization, in order to avoid cardinality constraints -\* If T is different from 1, use the general operators: -\* AtLeastT1(S) == Cardinality(S) >= THRESHOLD1 -\* AtLeastT2(S) == Cardinality(S) >= THRESHOLD2 -AtLeastT1(S) == \E x, y \in S: x /= y -AtLeastT2(S) == \E x, y, z \in S: x /= y /\ x /= z /\ y /= z - -ValueT == Int -RoundT == Int -TimeoutT == <> \* process, height, round -(* APALACHE-END *) - -FaultyProposals == - [src: Faulty, proposal: Values, validRound: Rounds \cup {-1}] - -FaultyPrevotes == [src: Faulty, hash: Values] - -FaultyPrecommits == [src: Faulty, hash: Values] - -ConstInit == PropFun \in [Heights \X Rounds -> Procs] - - -\* these variables are exactly as in the pseudo-code -VARIABLES h, round, step, decision, lockedValue, lockedRound, validValue, validRound - -\* book-keeping variables -VARIABLES msgsPropose, \* the propose messages broadcasted in the system, a function Heights \X Rounds -> set of messages - msgsPrevote, \* the prevote messages broadcasted in the system, a function Heights \X Rounds -> set of messages - msgsPrecommit, \* the precommit messages broadcasted in the system, a function Heights \X Rounds -> set of messages - oldEvents, \* the messages processed once, as expressed by "for the first time" - timeoutPropose, \* a set of proposed timeouts: <> - timeoutPrevote, \* a set of proposed timeouts: <> - timeoutPrecommit \* a set of proposed timeouts: <> - -\* this is needed for UNCHANGED -vars == <> - -\* A function which gives the proposer for a given round at a given height. -\* Here we use round robin. As Procs and Faulty are assigned non-deterministically, -\* it does not really matter who starts first. -Proposer(ht, rd) == PropFun[ht, rd] \*1 + ((ht + rd) % N) - -Id(v) == v - -IsValid(v) == v \in ValidValues - -\* here we start with StartRound(0) -Init == - /\ h = [p \in Procs |-> 0] - /\ round = [p \in Procs |-> 0] - /\ step = [p \in Procs |-> "PROPOSE"] - /\ decision = [p \in Procs |-> [ht \in Heights |-> nil]] - /\ lockedValue = [p \in Procs |-> nil] - /\ lockedRound = [p \in Procs |-> -1] - /\ validValue = [p \in Procs |-> nil] - /\ validRound = [p \in Procs |-> -1] - /\ \E v \in Values: - /\ msgsPropose = - [<> \in Heights \X Rounds |-> - IF ht = 0 /\ rd = 0 - THEN {[src |-> Proposer(0, 0), - proposal |-> v, validRound |-> -1]} \cup FaultyProposals - ELSE FaultyProposals \* only faulty messages - ] - /\ msgsPrevote = [<> \in Heights \X Rounds |-> FaultyPrevotes] - /\ msgsPrecommit = [<> \in Heights \X Rounds |-> FaultyPrecommits] - /\ oldEvents = {} <: {ET} - /\ timeoutPropose = { <> : p \in Procs \ {Proposer(0, 0)}} - /\ timeoutPrevote = {} <: {TimeoutT} \* no PREVOTE timeouts - /\ timeoutPrecommit = {} <: {TimeoutT} \* no PRECOMMIT timeouts - -\* lines 22-27 -UponProposalInPropose(p) == - \E v \in Values: - /\ step[p] = "PROPOSE" \* line 22 - /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> -1] - \in msgsPropose[h[p], round[p]] \* line 22 - /\ LET isGood == IsValid(v) /\ (lockedRound[p] = -1 \/ lockedValue[p] = v) IN \* line 23 - LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} - IN \* lines 24-26 - msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = - msgsPrevote[h[p], round[p]] \cup newMsgs] - /\ step' = [step EXCEPT ![p] = "PREVOTE"] - /\ UNCHANGED <> - -\* lines 28-33 -UponProposalInProposeAndPrevote(p) == - \E v \in Values, vr \in Rounds: - /\ step[p] = "PROPOSE" /\ 0 <= vr /\ vr < round[p] \* line 28, the while part - /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] - \in msgsPropose[h[p], round[p]] \* line 28 - /\ LET PV == { m \in msgsPrevote[h[p], vr]: m.hash = Id(v) } IN - AtLeastT2(PV) \* line 28 - /\ LET isGood == IsValid(v) /\ (lockedRound[p] <= vr \/ lockedValue[p] = v) IN \* line 29 - LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} - IN \* lines 30-32 - msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = - msgsPrevote[h[p], round[p]] \cup newMsgs] - /\ step' = [step EXCEPT ![p] = "PREVOTE"] - /\ UNCHANGED <> - -\* lines 34-35 -UponPrevoteFirstTime(p) == - /\ step[p] = "PREVOTE" \* line 34 - /\ AtLeastT2(msgsPrevote[h[p], round[p]]) \* line 34 - /\ LET event == [type |-> "PREVOTE", src |-> p, - h |-> h[p], round |-> round[p], value |-> nil] - IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* process it only once - /\ timeoutPrevote' = timeoutPrevote \cup {<>} \* line 35 - /\ UNCHANGED <> - -\* lines 36-46 -UponProposalInPrevoteOrCommitAndPrevote(p) == - \E v \in ValidValues, vr \in Rounds \cup {-1}: - /\ step[p] \in {"PREVOTE", "PRECOMMIT"} \* line 36 - /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] - \in msgsPropose[h[p], round[p]] \* line 36 - /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], - round |-> round[p], value |-> Id(v)] IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* record that it should not happen again - /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = Id(v) } IN - AtLeastT2(PV) \* line 36 - /\ lockedValue' = - IF step[p] = "PREVOTE" - THEN [lockedValue EXCEPT ![p] = v] \* line 38 - ELSE lockedValue \* else of line 37 - /\ lockedRound' = - IF step[p] = "PREVOTE" - THEN [lockedRound EXCEPT ![p] = round[p]] \* line 39 - ELSE lockedRound \* else of line 37 - /\ LET newMsgs == - IF step[p] = "PREVOTE" - THEN {[src |-> p, hash |-> Id(v)]} \* line 40 - ELSE {} <: {PrecommitT} - IN \* else of line 37 - msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = - msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 40, or else of 37 - /\ step' = - IF step[p] = "PREVOTE" - THEN [step EXCEPT ![p] = "PRECOMMIT"] - ELSE step \* line 41 - /\ validValue' = [validValue EXCEPT ![p] = v] \* line 42 - /\ validRound' = [validRound EXCEPT ![p] = round[p]] \* line 43 - /\ UNCHANGED <> - -\* Apparently, this action is needed to deal with a value proposed by a Byzantine process -\* lines 44-46 -UponPrevoteNil(p) == - /\ step[p] = "PREVOTE" \* line 44 - /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = nil } - IN - AtLeastT2(PV) \* line 34 - /\ step' = [step EXCEPT ![p] = "PRECOMMIT"] - /\ LET newMsgs == {[src |-> p, hash |-> nil]} \* line 45 - IN - msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = - msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 45 - /\ UNCHANGED <> - -\* lines 47-48 -UponPrecommitFirstTime(p) == - /\ AtLeastT2(msgsPrecommit[h[p], round[p]]) \* line 47 - /\ LET event == [type |-> "PRECOMMIT", src |-> p, - h |-> h[p], round |-> round[p], value |-> nil] - IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* process it only once - /\ timeoutPrecommit' = timeoutPrecommit \cup {<>} \* line 48 - /\ UNCHANGED <> - -\* lines 11-21 -StartRound(p, ht, r) == - /\ round' = [round EXCEPT ![p] = r] - /\ step' = [step EXCEPT ![p] = "PROPOSE"] - /\ \E v \in ValidValues: \* lines 14-21 - LET proposal == IF validValue[p] /= nil THEN validValue[p] ELSE v IN - LET newMsgs == - IF p = Proposer(ht, r) - THEN {[src |-> p, proposal |-> proposal, validRound |-> validRound[p]]} - ELSE {} <: {ProposalT} - IN - msgsPropose' = [msgsPropose EXCEPT ![ht, r] = - msgsPropose[ht, r] \cup newMsgs] \* line 19 - /\ LET newTimeouts == \* line 21 - IF p = Proposer(ht, r) - THEN {} <: {TimeoutT} \* no new timeouts - ELSE { <> } - IN - timeoutPropose' = timeoutPropose \cup newTimeouts - -\* lines 49-54 -UponProposalInPrecommitNoDecision(p) == - /\ h[p] + 1 \in Heights - \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING - /\ decision[p][h[p]] = nil \* line 49 - /\ \E v \in ValidValues (* line 50*) , r \in Rounds, vr \in Rounds \cup {-1}: - /\ [src |-> Proposer(h[p], r), proposal |-> v, validRound |-> vr] - \in msgsPropose[h[p], r] \* line 49 - /\ LET PV == { m \in msgsPrecommit[h[p], r]: m.hash = Id(v) } IN - AtLeastT2(PV) \* line 49 - /\ decision' = [decision EXCEPT ![p][h[p]] = v] \* update the decision, line 51 - /\ h' = [h EXCEPT ![p] = h[p] + 1] \* line 52 - \* line 53 - /\ lockedRound' = [lockedRound EXCEPT ![p] = -1] - /\ lockedValue' = [lockedValue EXCEPT ![p] = nil] - /\ validRound' = [validRound EXCEPT ![p] = -1] - /\ validValue' = [validValue EXCEPT ![p] = nil] - \* What does it mean to reset the message buffer? Do it for one process only? - /\ StartRound(p, h[p] + 1, 0) - /\ UNCHANGED <> - -\* lines 55-56 -UponCatchupRound(p) == - \E r \in Rounds: - /\ r > round[p] - /\ LET ps == { m.src : m \in msgsPropose[h[p], r]} IN - LET pv == { m.src : m \in msgsPrevote[h[p], r]} IN - LET pc == { m.src : m \in msgsPrecommit[h[p], r]} IN - AtLeastT1(ps \cup pv \cup pc) \* line 55 - /\ StartRound(p, h[p], r) - /\ UNCHANGED <> - -\* lines 57-60 -OnTimeoutPropose(p) == - \E tm \in timeoutPropose: \* a timeout occurs - /\ tm[1] = p - /\ timeoutPropose' = timeoutPropose \ {tm} \* remove from the future timeouts - /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PROPOSE" IN - /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PREVOTE"] ELSE step \* line 60 - /\ LET newMsgs == - IF UpdateNeeded - THEN {[src |-> tm[1], hash |-> nil]} \* line 59 - ELSE {} <: {PrevoteT} \* else of line 58 - IN \* line 59, or else of 58 - msgsPrevote' = [msgsPrevote EXCEPT ![tm[2], tm[3]] = - msgsPrevote[tm[2], tm[3]] \cup newMsgs] - /\ UNCHANGED <> - -\* lines 61-64 -OnTimeoutPrevote(p) == - \E tm \in timeoutPrevote: \* a timeout occurs - /\ tm[1] = p - /\ timeoutPrevote' = timeoutPrevote \ {tm} \* remove from the future timeouts - /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PREVOTE" IN - /\ step' = - IF UpdateNeeded - THEN [step EXCEPT ![p] = "PRECOMMIT"] - ELSE step \* line 64 - /\ LET newMsgs == - IF UpdateNeeded - THEN {[src |-> tm[1], hash |-> nil]} \* line 63 - ELSE {} <: {PrecommitT} \* else of line 62 - IN \* line 63, or else of 62 - msgsPrecommit' = [msgsPrecommit EXCEPT ![tm[2], tm[3]] = - msgsPrecommit[tm[2], tm[3]] \cup newMsgs] - /\ UNCHANGED <> - -\* lines 65-67 -OnTimeoutPrecommitOutside(p) == - \E tm \in timeoutPrecommit: \* a timeout occurs - /\ tm[1] = p - /\ (tm[2] /= h[p] \/ tm[3] /= round[p]) \* but we are in another round or height - /\ timeoutPrecommit' = timeoutPrecommit \ {tm} \* remove from the future timeouts - /\ UNCHANGED <> - -\* lines 65-67 -OnTimeoutPrecommitInside(p) == - /\ round[p] + 1 \in Rounds - \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING - /\ <> \in timeoutPrecommit \* the timeout occurs for the current round and height - /\ timeoutPrecommit' = timeoutPrecommit \ {<>} \* remove from the future timeouts - /\ StartRound(p, h[p], round[p] + 1) - /\ UNCHANGED <> - - -Next == - \/ \E p \in Procs: - \/ UponProposalInPropose(p) - \/ UponProposalInProposeAndPrevote(p) - \/ UponPrevoteFirstTime(p) - \/ UponProposalInPrevoteOrCommitAndPrevote(p) - \/ UponPrevoteNil(p) \* FIXME: disabled for model checking - \/ UponPrecommitFirstTime(p) - \/ UponProposalInPrecommitNoDecision(p) - \/ UponCatchupRound(p) - \/ OnTimeoutPropose(p) - \/ OnTimeoutPrevote(p) - \/ OnTimeoutPrecommitOutside(p) - \/ OnTimeoutPrecommitInside(p) - \* a safeguard to prevent deadlocks when the algorithm goes to further heights or rounds - \*\/ UNCHANGED vars - -\* safety -Agreement == - \A p, q \in Procs, ht \in Heights: - \/ decision[p][ht] = nil - \/ decision[q][ht] = nil - \/ decision[p][ht] = decision[q][ht] - -\* simple reachability properties to make sure that the algorithm is doing anything useful -NoDecision == \A p \in Procs, ht \in Heights: decision[p][ht] = nil - -NoPrecommit == \A p \in Procs: step[p] /= "PRECOMMIT" - -NoTwoLockedValues == - \A p, q \in Procs: - h[p] = h[q] => lockedValue[p] = nil \/ lockedValue[q] = nil \/ lockedValue[p] = lockedValue[q] - -NoTwoLockedRounds == - \A p, q \in Procs: - h[p] = h[q] => lockedRound[p] = -1 \/ lockedRound[q] = -1 \/ lockedRound[p] = lockedRound[q] - - -============================================================================= -\* Modification History -\* Last modified Fri Mar 22 08:57:10 CET 2019 by igor -\* Created Fri Mar 15 10:30:17 CET 2019 by igor diff --git a/docs/spec/tendermint-fork/Tendermint4n4f2.tla b/docs/spec/tendermint-fork/Tendermint4n4f2.tla deleted file mode 100644 index 57c3e130c..000000000 --- a/docs/spec/tendermint-fork/Tendermint4n4f2.tla +++ /dev/null @@ -1,392 +0,0 @@ ------------------------------ MODULE Tendermint4n4f2 -------------------------- -(* - A TLA+ specification by Igor Konnov - of Tendermint consensus by Ethan Buchman, Jae Kwon, and Zarko Milosevic. - - For the moment, we assume the following: - - 1. Every process has the voting power of 1 (this seems to be complete). - 2. Timeouts are non-deterministic (works for safety). - 3. The proposer function is completely non-deterministic (works for safety). - - It took me 4 hours to translate the pseudo-code to TLA+. - Then it took me several days to make it more efficient for the model checker. - - Version 3: assuming that f = 1, - using AtLeastT1(S) and AtLeastT2(s) instead of - Cardinality(S) >= f + 1 and Cardinality(S) >= 2f + 1 - - Version 4: simplified record types, as we are using separate variables - for different message types and different indices for heights and rounds. - Injecting all Byzantine messages in the initial states. - *) - -EXTENDS Integers, FiniteSets - -CONSTANTS PropFun \* the proposer function - -N == 4 \* the total number of processes: correct and faulty -T == 1 \* an upper bound on the number of Byzantine processes -F == 2 \* the number of Byzantine processes -Procs == 1..N-F -Faulty == N-F+1..N -Heights == 0..1 \* the set of consensus instances -Rounds == 0..2 \* the set of possible rounds, give a bit more freedom to the solver -ValidValues == {0, 1} \* e.g., picked by a correct process, or a faulty one -InvalidValues == {2} \* e.g., sent by a Byzantine process -Values == ValidValues \cup InvalidValues \* all values -nil == -1 - -\* these are two tresholds that are used in the algorithm -THRESHOLD1 == T + 1 -THRESHOLD2 == 2 * T + 1 - -(* APALACHE-BEGIN annotations *) -a <: b == a - -MT == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, - proposal |-> Int, validRound |-> Int, hash |-> Int] -ProposalT == [src |-> Int, proposal |-> Int, validRound |-> Int] -PrevoteT == [src |-> Int, hash |-> Int] -PrecommitT == PrevoteT -ET == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, value |-> Int] \* processed events, "for the first time" - -\* This is an optimization, in order to avoid cardinality constraints -\* If T is different from 1, use the general operators: -\* AtLeastT1(S) == Cardinality(S) >= THRESHOLD1 -\* AtLeastT2(S) == Cardinality(S) >= THRESHOLD2 -AtLeastT1(S) == \E x, y \in S: x /= y -AtLeastT2(S) == \E x, y, z \in S: x /= y /\ x /= z /\ y /= z - -ValueT == Int -RoundT == Int -TimeoutT == <> \* process, height, round -(* APALACHE-END *) - -FaultyProposals == - [src: Faulty, proposal: Values, validRound: Rounds \cup {-1}] - -FaultyPrevotes == [src: Faulty, hash: Values] - -FaultyPrecommits == [src: Faulty, hash: Values] - -ConstInit == PropFun \in [Heights \X Rounds -> Procs] - - -\* these variables are exactly as in the pseudo-code -VARIABLES h, round, step, decision, lockedValue, lockedRound, validValue, validRound - -\* book-keeping variables -VARIABLES msgsPropose, \* the propose messages broadcasted in the system, a function Heights \X Rounds -> set of messages - msgsPrevote, \* the prevote messages broadcasted in the system, a function Heights \X Rounds -> set of messages - msgsPrecommit, \* the precommit messages broadcasted in the system, a function Heights \X Rounds -> set of messages - oldEvents, \* the messages processed once, as expressed by "for the first time" - timeoutPropose, \* a set of proposed timeouts: <> - timeoutPrevote, \* a set of proposed timeouts: <> - timeoutPrecommit \* a set of proposed timeouts: <> - -\* this is needed for UNCHANGED -vars == <> - -\* A function which gives the proposer for a given round at a given height. -\* Here we use round robin. As Procs and Faulty are assigned non-deterministically, -\* it does not really matter who starts first. -Proposer(ht, rd) == PropFun[ht, rd] \*1 + ((ht + rd) % N) - -Id(v) == v - -IsValid(v) == v \in ValidValues - -\* here we start with StartRound(0) -Init == - /\ h = [p \in Procs |-> 0] - /\ round = [p \in Procs |-> 0] - /\ step = [p \in Procs |-> "PROPOSE"] - /\ decision = [p \in Procs |-> [ht \in Heights |-> nil]] - /\ lockedValue = [p \in Procs |-> nil] - /\ lockedRound = [p \in Procs |-> -1] - /\ validValue = [p \in Procs |-> nil] - /\ validRound = [p \in Procs |-> -1] - /\ \E v \in Values: - /\ msgsPropose = - [<> \in Heights \X Rounds |-> - IF ht = 0 /\ rd = 0 - THEN {[src |-> Proposer(0, 0), - proposal |-> v, validRound |-> -1]} \cup FaultyProposals - ELSE FaultyProposals \* only faulty messages - ] - /\ msgsPrevote = [<> \in Heights \X Rounds |-> FaultyPrevotes] - /\ msgsPrecommit = [<> \in Heights \X Rounds |-> FaultyPrecommits] - /\ oldEvents = {} <: {ET} - /\ timeoutPropose = { <> : p \in Procs \ {Proposer(0, 0)}} - /\ timeoutPrevote = {} <: {TimeoutT} \* no PREVOTE timeouts - /\ timeoutPrecommit = {} <: {TimeoutT} \* no PRECOMMIT timeouts - -\* lines 22-27 -UponProposalInPropose(p) == - \E v \in Values: - /\ step[p] = "PROPOSE" \* line 22 - /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> -1] - \in msgsPropose[h[p], round[p]] \* line 22 - /\ LET isGood == IsValid(v) /\ (lockedRound[p] = -1 \/ lockedValue[p] = v) IN \* line 23 - LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} - IN \* lines 24-26 - msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = - msgsPrevote[h[p], round[p]] \cup newMsgs] - /\ step' = [step EXCEPT ![p] = "PREVOTE"] - /\ UNCHANGED <> - -\* lines 28-33 -UponProposalInProposeAndPrevote(p) == - \E v \in Values, vr \in Rounds: - /\ step[p] = "PROPOSE" /\ 0 <= vr /\ vr < round[p] \* line 28, the while part - /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] - \in msgsPropose[h[p], round[p]] \* line 28 - /\ LET PV == { m \in msgsPrevote[h[p], vr]: m.hash = Id(v) } IN - AtLeastT2(PV) \* line 28 - /\ LET isGood == IsValid(v) /\ (lockedRound[p] <= vr \/ lockedValue[p] = v) IN \* line 29 - LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} - IN \* lines 30-32 - msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = - msgsPrevote[h[p], round[p]] \cup newMsgs] - /\ step' = [step EXCEPT ![p] = "PREVOTE"] - /\ UNCHANGED <> - -\* lines 34-35 -UponPrevoteFirstTime(p) == - /\ step[p] = "PREVOTE" \* line 34 - /\ AtLeastT2(msgsPrevote[h[p], round[p]]) \* line 34 - /\ LET event == [type |-> "PREVOTE", src |-> p, - h |-> h[p], round |-> round[p], value |-> nil] - IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* process it only once - /\ timeoutPrevote' = timeoutPrevote \cup {<>} \* line 35 - /\ UNCHANGED <> - -\* lines 36-46 -UponProposalInPrevoteOrCommitAndPrevote(p) == - \E v \in ValidValues, vr \in Rounds \cup {-1}: - /\ step[p] \in {"PREVOTE", "PRECOMMIT"} \* line 36 - /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] - \in msgsPropose[h[p], round[p]] \* line 36 - /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], - round |-> round[p], value |-> Id(v)] IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* record that it should not happen again - /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = Id(v) } IN - AtLeastT2(PV) \* line 36 - /\ lockedValue' = - IF step[p] = "PREVOTE" - THEN [lockedValue EXCEPT ![p] = v] \* line 38 - ELSE lockedValue \* else of line 37 - /\ lockedRound' = - IF step[p] = "PREVOTE" - THEN [lockedRound EXCEPT ![p] = round[p]] \* line 39 - ELSE lockedRound \* else of line 37 - /\ LET newMsgs == - IF step[p] = "PREVOTE" - THEN {[src |-> p, hash |-> Id(v)]} \* line 40 - ELSE {} <: {PrecommitT} - IN \* else of line 37 - msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = - msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 40, or else of 37 - /\ step' = - IF step[p] = "PREVOTE" - THEN [step EXCEPT ![p] = "PRECOMMIT"] - ELSE step \* line 41 - /\ validValue' = [validValue EXCEPT ![p] = v] \* line 42 - /\ validRound' = [validRound EXCEPT ![p] = round[p]] \* line 43 - /\ UNCHANGED <> - -\* Apparently, this action is needed to deal with a value proposed by a Byzantine process -\* lines 44-46 -UponPrevoteNil(p) == - /\ step[p] = "PREVOTE" \* line 44 - /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = nil } - IN - AtLeastT2(PV) \* line 34 - /\ step' = [step EXCEPT ![p] = "PRECOMMIT"] - /\ LET newMsgs == {[src |-> p, hash |-> nil]} \* line 45 - IN - msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = - msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 45 - /\ UNCHANGED <> - -\* lines 47-48 -UponPrecommitFirstTime(p) == - /\ AtLeastT2(msgsPrecommit[h[p], round[p]]) \* line 47 - /\ LET event == [type |-> "PRECOMMIT", src |-> p, - h |-> h[p], round |-> round[p], value |-> nil] - IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* process it only once - /\ timeoutPrecommit' = timeoutPrecommit \cup {<>} \* line 48 - /\ UNCHANGED <> - -\* lines 11-21 -StartRound(p, ht, r) == - /\ round' = [round EXCEPT ![p] = r] - /\ step' = [step EXCEPT ![p] = "PROPOSE"] - /\ \E v \in ValidValues: \* lines 14-21 - LET proposal == IF validValue[p] /= nil THEN validValue[p] ELSE v IN - LET newMsgs == - IF p = Proposer(ht, r) - THEN {[src |-> p, proposal |-> proposal, validRound |-> validRound[p]]} - ELSE {} <: {ProposalT} - IN - msgsPropose' = [msgsPropose EXCEPT ![ht, r] = - msgsPropose[ht, r] \cup newMsgs] \* line 19 - /\ LET newTimeouts == \* line 21 - IF p = Proposer(ht, r) - THEN {} <: {TimeoutT} \* no new timeouts - ELSE { <> } - IN - timeoutPropose' = timeoutPropose \cup newTimeouts - -\* lines 49-54 -UponProposalInPrecommitNoDecision(p) == - /\ h[p] + 1 \in Heights - \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING - /\ decision[p][h[p]] = nil \* line 49 - /\ \E v \in ValidValues (* line 50*) , r \in Rounds, vr \in Rounds \cup {-1}: - /\ [src |-> Proposer(h[p], r), proposal |-> v, validRound |-> vr] - \in msgsPropose[h[p], r] \* line 49 - /\ LET PV == { m \in msgsPrecommit[h[p], r]: m.hash = Id(v) } IN - AtLeastT2(PV) \* line 49 - /\ decision' = [decision EXCEPT ![p][h[p]] = v] \* update the decision, line 51 - /\ h' = [h EXCEPT ![p] = h[p] + 1] \* line 52 - \* line 53 - /\ lockedRound' = [lockedRound EXCEPT ![p] = -1] - /\ lockedValue' = [lockedValue EXCEPT ![p] = nil] - /\ validRound' = [validRound EXCEPT ![p] = -1] - /\ validValue' = [validValue EXCEPT ![p] = nil] - \* What does it mean to reset the message buffer? Do it for one process only? - /\ StartRound(p, h[p] + 1, 0) - /\ UNCHANGED <> - -\* lines 55-56 -UponCatchupRound(p) == - \E r \in Rounds: - /\ r > round[p] - /\ LET ps == { m.src : m \in msgsPropose[h[p], r]} IN - LET pv == { m.src : m \in msgsPrevote[h[p], r]} IN - LET pc == { m.src : m \in msgsPrecommit[h[p], r]} IN - AtLeastT1(ps \cup pv \cup pc) \* line 55 - /\ StartRound(p, h[p], r) - /\ UNCHANGED <> - -\* lines 57-60 -OnTimeoutPropose(p) == - \E tm \in timeoutPropose: \* a timeout occurs - /\ tm[1] = p - /\ timeoutPropose' = timeoutPropose \ {tm} \* remove from the future timeouts - /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PROPOSE" IN - /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PREVOTE"] ELSE step \* line 60 - /\ LET newMsgs == - IF UpdateNeeded - THEN {[src |-> tm[1], hash |-> nil]} \* line 59 - ELSE {} <: {PrevoteT} \* else of line 58 - IN \* line 59, or else of 58 - msgsPrevote' = [msgsPrevote EXCEPT ![tm[2], tm[3]] = - msgsPrevote[tm[2], tm[3]] \cup newMsgs] - /\ UNCHANGED <> - -\* lines 61-64 -OnTimeoutPrevote(p) == - \E tm \in timeoutPrevote: \* a timeout occurs - /\ tm[1] = p - /\ timeoutPrevote' = timeoutPrevote \ {tm} \* remove from the future timeouts - /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PREVOTE" IN - /\ step' = - IF UpdateNeeded - THEN [step EXCEPT ![p] = "PRECOMMIT"] - ELSE step \* line 64 - /\ LET newMsgs == - IF UpdateNeeded - THEN {[src |-> tm[1], hash |-> nil]} \* line 63 - ELSE {} <: {PrecommitT} \* else of line 62 - IN \* line 63, or else of 62 - msgsPrecommit' = [msgsPrecommit EXCEPT ![tm[2], tm[3]] = - msgsPrecommit[tm[2], tm[3]] \cup newMsgs] - /\ UNCHANGED <> - -\* lines 65-67 -OnTimeoutPrecommitOutside(p) == - \E tm \in timeoutPrecommit: \* a timeout occurs - /\ tm[1] = p - /\ (tm[2] /= h[p] \/ tm[3] /= round[p]) \* but we are in another round or height - /\ timeoutPrecommit' = timeoutPrecommit \ {tm} \* remove from the future timeouts - /\ UNCHANGED <> - -\* lines 65-67 -OnTimeoutPrecommitInside(p) == - /\ round[p] + 1 \in Rounds - \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING - /\ <> \in timeoutPrecommit \* the timeout occurs for the current round and height - /\ timeoutPrecommit' = timeoutPrecommit \ {<>} \* remove from the future timeouts - /\ StartRound(p, h[p], round[p] + 1) - /\ UNCHANGED <> - - -Next == - \/ \E p \in Procs: - \/ UponProposalInPropose(p) - \/ UponProposalInProposeAndPrevote(p) - \/ UponPrevoteFirstTime(p) - \/ UponProposalInPrevoteOrCommitAndPrevote(p) - \/ UponPrevoteNil(p) \* FIXME: disabled for model checking - \/ UponPrecommitFirstTime(p) - \/ UponProposalInPrecommitNoDecision(p) - \/ UponCatchupRound(p) - \/ OnTimeoutPropose(p) - \/ OnTimeoutPrevote(p) - \/ OnTimeoutPrecommitOutside(p) - \/ OnTimeoutPrecommitInside(p) - \* a safeguard to prevent deadlocks when the algorithm goes to further heights or rounds - \*\/ UNCHANGED vars - -\* safety -Agreement == - \A p, q \in Procs, ht \in Heights: - \/ decision[p][ht] = nil - \/ decision[q][ht] = nil - \/ decision[p][ht] = decision[q][ht] - -\* simple reachability properties to make sure that the algorithm is doing anything useful -NoDecision == \A p \in Procs, ht \in Heights: decision[p][ht] = nil - -NoPrecommit == \A p \in Procs: step[p] /= "PRECOMMIT" - -NoTwoLockedValues == - \A p, q \in Procs: - h[p] = h[q] => lockedValue[p] = nil \/ lockedValue[q] = nil \/ lockedValue[p] = lockedValue[q] - -NoTwoLockedRounds == - \A p, q \in Procs: - h[p] = h[q] => lockedRound[p] = -1 \/ lockedRound[q] = -1 \/ lockedRound[p] = lockedRound[q] - - -============================================================================= -\* Modification History -\* Last modified Fri Mar 22 08:57:10 CET 2019 by igor -\* Created Fri Mar 15 10:30:17 CET 2019 by igor diff --git a/docs/spec/tendermint-fork/Tendermint4n5f1T3.tla b/docs/spec/tendermint-fork/Tendermint4n5f1T3.tla deleted file mode 100644 index 829494d0a..000000000 --- a/docs/spec/tendermint-fork/Tendermint4n5f1T3.tla +++ /dev/null @@ -1,393 +0,0 @@ ----------------------- MODULE Tendermint4n5f1T3 ----------------------------- -(* - A TLA+ specification by Igor Konnov - of Tendermint consensus by Ethan Buchman, Jae Kwon, and Zarko Milosevic. - - For the moment, we assume the following: - - 1. Every process has the voting power of 1 (this seems to be complete). - 2. Timeouts are non-deterministic (works for safety). - 3. The proposer function is completely non-deterministic (works for safety). - - It took me 4 hours to translate the pseudo-code to TLA+. - Then it took me several days to make it more efficient for the model checker. - - Version 3: assuming that f = 1, - using AtLeastT1(S) and AtLeastT2(s) instead of - Cardinality(S) >= f + 1 and Cardinality(S) >= 2f + 1 - - Version 4: simplified record types, as we are using separate variables - for different message types and different indices for heights and rounds. - Injecting all Byzantine messages in the initial states. - *) - -EXTENDS Integers, FiniteSets - -CONSTANTS PropFun \* the proposer function - -N == 5 \* the total number of processes: correct and faulty -T == 1 \* an upper bound on the number of Byzantine processes -F == 1 \* the number of Byzantine processes -Procs == 1..N-F -Faulty == N-F+1..N -Heights == 0..1 \* the set of consensus instances -Rounds == 0..2 \* the set of possible rounds, give a bit more freedom to the solver -ValidValues == {0, 1} \* e.g., picked by a correct process, or a faulty one -InvalidValues == {2} \* e.g., sent by a Byzantine process -Values == ValidValues \cup InvalidValues \* all values -nil == -1 - -\* these are two tresholds that are used in the algorithm -THRESHOLD1 == T + 1 -THRESHOLD2 == N - T - -(* APALACHE-BEGIN annotations *) -a <: b == a - -MT == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, - proposal |-> Int, validRound |-> Int, hash |-> Int] -ProposalT == [src |-> Int, proposal |-> Int, validRound |-> Int] -PrevoteT == [src |-> Int, hash |-> Int] -PrecommitT == PrevoteT -ET == [type |-> STRING, src |-> Int, h |-> Int, round |-> Int, value |-> Int] \* processed events, "for the first time" - -\* This is an optimization, in order to avoid cardinality constraints -\* If T is different from 1, use the general operators: -\*AtLeastT1(S) == Cardinality(S) >= THRESHOLD1 -\*AtLeastT2(S) == Cardinality(S) >= THRESHOLD2 -AtLeastT1(S) == \E x, y \in S: x /= y -AtLeastT2(S) == \E w, x, y, z \in S: - x /= y /\ x /= z /\ y /= z /\ w /= x /\ w /= y /\ w /= z - -ValueT == Int -RoundT == Int -TimeoutT == <> \* process, height, round -(* APALACHE-END *) - -FaultyProposals == - [src: Faulty, proposal: Values, validRound: Rounds \cup {-1}] - -FaultyPrevotes == [src: Faulty, hash: Values] - -FaultyPrecommits == [src: Faulty, hash: Values] - -ConstInit == PropFun \in [Heights \X Rounds -> Procs] - - -\* these variables are exactly as in the pseudo-code -VARIABLES h, round, step, decision, lockedValue, lockedRound, validValue, validRound - -\* book-keeping variables -VARIABLES msgsPropose, \* the propose messages broadcasted in the system, a function Heights \X Rounds -> set of messages - msgsPrevote, \* the prevote messages broadcasted in the system, a function Heights \X Rounds -> set of messages - msgsPrecommit, \* the precommit messages broadcasted in the system, a function Heights \X Rounds -> set of messages - oldEvents, \* the messages processed once, as expressed by "for the first time" - timeoutPropose, \* a set of proposed timeouts: <> - timeoutPrevote, \* a set of proposed timeouts: <> - timeoutPrecommit \* a set of proposed timeouts: <> - -\* this is needed for UNCHANGED -vars == <> - -\* A function which gives the proposer for a given round at a given height. -\* Here we use round robin. As Procs and Faulty are assigned non-deterministically, -\* it does not really matter who starts first. -Proposer(ht, rd) == PropFun[ht, rd] \*1 + ((ht + rd) % N) - -Id(v) == v - -IsValid(v) == v \in ValidValues - -\* here we start with StartRound(0) -Init == - /\ h = [p \in Procs |-> 0] - /\ round = [p \in Procs |-> 0] - /\ step = [p \in Procs |-> "PROPOSE"] - /\ decision = [p \in Procs |-> [ht \in Heights |-> nil]] - /\ lockedValue = [p \in Procs |-> nil] - /\ lockedRound = [p \in Procs |-> -1] - /\ validValue = [p \in Procs |-> nil] - /\ validRound = [p \in Procs |-> -1] - /\ \E v \in Values: - /\ msgsPropose = - [<> \in Heights \X Rounds |-> - IF ht = 0 /\ rd = 0 - THEN {[src |-> Proposer(0, 0), - proposal |-> v, validRound |-> -1]} \cup FaultyProposals - ELSE FaultyProposals \* only faulty messages - ] - /\ msgsPrevote = [<> \in Heights \X Rounds |-> FaultyPrevotes] - /\ msgsPrecommit = [<> \in Heights \X Rounds |-> FaultyPrecommits] - /\ oldEvents = {} <: {ET} - /\ timeoutPropose = { <> : p \in Procs \ {Proposer(0, 0)}} - /\ timeoutPrevote = {} <: {TimeoutT} \* no PREVOTE timeouts - /\ timeoutPrecommit = {} <: {TimeoutT} \* no PRECOMMIT timeouts - -\* lines 22-27 -UponProposalInPropose(p) == - \E v \in Values: - /\ step[p] = "PROPOSE" \* line 22 - /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> -1] - \in msgsPropose[h[p], round[p]] \* line 22 - /\ LET isGood == IsValid(v) /\ (lockedRound[p] = -1 \/ lockedValue[p] = v) IN \* line 23 - LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} - IN \* lines 24-26 - msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = - msgsPrevote[h[p], round[p]] \cup newMsgs] - /\ step' = [step EXCEPT ![p] = "PREVOTE"] - /\ UNCHANGED <> - -\* lines 28-33 -UponProposalInProposeAndPrevote(p) == - \E v \in Values, vr \in Rounds: - /\ step[p] = "PROPOSE" /\ 0 <= vr /\ vr < round[p] \* line 28, the while part - /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] - \in msgsPropose[h[p], round[p]] \* line 28 - /\ LET PV == { m \in msgsPrevote[h[p], vr]: m.hash = Id(v) } IN - AtLeastT2(PV) \* line 28 - /\ LET isGood == IsValid(v) /\ (lockedRound[p] <= vr \/ lockedValue[p] = v) IN \* line 29 - LET newMsgs == {[src |-> p, hash |-> IF isGood THEN Id(v) ELSE nil]} - IN \* lines 30-32 - msgsPrevote' = [msgsPrevote EXCEPT ![h[p], round[p]] = - msgsPrevote[h[p], round[p]] \cup newMsgs] - /\ step' = [step EXCEPT ![p] = "PREVOTE"] - /\ UNCHANGED <> - -\* lines 34-35 -UponPrevoteFirstTime(p) == - /\ step[p] = "PREVOTE" \* line 34 - /\ AtLeastT2(msgsPrevote[h[p], round[p]]) \* line 34 - /\ LET event == [type |-> "PREVOTE", src |-> p, - h |-> h[p], round |-> round[p], value |-> nil] - IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* process it only once - /\ timeoutPrevote' = timeoutPrevote \cup {<>} \* line 35 - /\ UNCHANGED <> - -\* lines 36-46 -UponProposalInPrevoteOrCommitAndPrevote(p) == - \E v \in ValidValues, vr \in Rounds \cup {-1}: - /\ step[p] \in {"PREVOTE", "PRECOMMIT"} \* line 36 - /\ [src |-> Proposer(h[p], round[p]), proposal |-> v, validRound |-> vr] - \in msgsPropose[h[p], round[p]] \* line 36 - /\ LET event == [type |-> "PREVOTE", src |-> p, h |-> h[p], - round |-> round[p], value |-> Id(v)] IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* record that it should not happen again - /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = Id(v) } IN - AtLeastT2(PV) \* line 36 - /\ lockedValue' = - IF step[p] = "PREVOTE" - THEN [lockedValue EXCEPT ![p] = v] \* line 38 - ELSE lockedValue \* else of line 37 - /\ lockedRound' = - IF step[p] = "PREVOTE" - THEN [lockedRound EXCEPT ![p] = round[p]] \* line 39 - ELSE lockedRound \* else of line 37 - /\ LET newMsgs == - IF step[p] = "PREVOTE" - THEN {[src |-> p, hash |-> Id(v)]} \* line 40 - ELSE {} <: {PrecommitT} - IN \* else of line 37 - msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = - msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 40, or else of 37 - /\ step' = - IF step[p] = "PREVOTE" - THEN [step EXCEPT ![p] = "PRECOMMIT"] - ELSE step \* line 41 - /\ validValue' = [validValue EXCEPT ![p] = v] \* line 42 - /\ validRound' = [validRound EXCEPT ![p] = round[p]] \* line 43 - /\ UNCHANGED <> - -\* Apparently, this action is needed to deal with a value proposed by a Byzantine process -\* lines 44-46 -UponPrevoteNil(p) == - /\ step[p] = "PREVOTE" \* line 44 - /\ LET PV == { m \in msgsPrevote[h[p], round[p]]: m.hash = nil } - IN - AtLeastT2(PV) \* line 34 - /\ step' = [step EXCEPT ![p] = "PRECOMMIT"] - /\ LET newMsgs == {[src |-> p, hash |-> nil]} \* line 45 - IN - msgsPrecommit' = [msgsPrecommit EXCEPT ![h[p], round[p]] = - msgsPrecommit[h[p], round[p]] \cup newMsgs] \* line 45 - /\ UNCHANGED <> - -\* lines 47-48 -UponPrecommitFirstTime(p) == - /\ AtLeastT2(msgsPrecommit[h[p], round[p]]) \* line 47 - /\ LET event == [type |-> "PRECOMMIT", src |-> p, - h |-> h[p], round |-> round[p], value |-> nil] - IN - /\ event \notin oldEvents \* for the first time - /\ oldEvents' = oldEvents \cup {event} \* process it only once - /\ timeoutPrecommit' = timeoutPrecommit \cup {<>} \* line 48 - /\ UNCHANGED <> - -\* lines 11-21 -StartRound(p, ht, r) == - /\ round' = [round EXCEPT ![p] = r] - /\ step' = [step EXCEPT ![p] = "PROPOSE"] - /\ \E v \in ValidValues: \* lines 14-21 - LET proposal == IF validValue[p] /= nil THEN validValue[p] ELSE v IN - LET newMsgs == - IF p = Proposer(ht, r) - THEN {[src |-> p, proposal |-> proposal, validRound |-> validRound[p]]} - ELSE {} <: {ProposalT} - IN - msgsPropose' = [msgsPropose EXCEPT ![ht, r] = - msgsPropose[ht, r] \cup newMsgs] \* line 19 - /\ LET newTimeouts == \* line 21 - IF p = Proposer(ht, r) - THEN {} <: {TimeoutT} \* no new timeouts - ELSE { <> } - IN - timeoutPropose' = timeoutPropose \cup newTimeouts - -\* lines 49-54 -UponProposalInPrecommitNoDecision(p) == - /\ h[p] + 1 \in Heights - \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING - /\ decision[p][h[p]] = nil \* line 49 - /\ \E v \in ValidValues (* line 50*) , r \in Rounds, vr \in Rounds \cup {-1}: - /\ [src |-> Proposer(h[p], r), proposal |-> v, validRound |-> vr] - \in msgsPropose[h[p], r] \* line 49 - /\ LET PV == { m \in msgsPrecommit[h[p], r]: m.hash = Id(v) } IN - AtLeastT2(PV) \* line 49 - /\ decision' = [decision EXCEPT ![p][h[p]] = v] \* update the decision, line 51 - /\ h' = [h EXCEPT ![p] = h[p] + 1] \* line 52 - \* line 53 - /\ lockedRound' = [lockedRound EXCEPT ![p] = -1] - /\ lockedValue' = [lockedValue EXCEPT ![p] = nil] - /\ validRound' = [validRound EXCEPT ![p] = -1] - /\ validValue' = [validValue EXCEPT ![p] = nil] - \* What does it mean to reset the message buffer? Do it for one process only? - /\ StartRound(p, h[p] + 1, 0) - /\ UNCHANGED <> - -\* lines 55-56 -UponCatchupRound(p) == - \E r \in Rounds: - /\ r > round[p] - /\ LET ps == { m.src : m \in msgsPropose[h[p], r]} IN - LET pv == { m.src : m \in msgsPrevote[h[p], r]} IN - LET pc == { m.src : m \in msgsPrecommit[h[p], r]} IN - AtLeastT1(ps \cup pv \cup pc) \* line 55 - /\ StartRound(p, h[p], r) - /\ UNCHANGED <> - -\* lines 57-60 -OnTimeoutPropose(p) == - \E tm \in timeoutPropose: \* a timeout occurs - /\ tm[1] = p - /\ timeoutPropose' = timeoutPropose \ {tm} \* remove from the future timeouts - /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PROPOSE" IN - /\ step' = IF UpdateNeeded THEN [step EXCEPT ![p] = "PREVOTE"] ELSE step \* line 60 - /\ LET newMsgs == - IF UpdateNeeded - THEN {[src |-> tm[1], hash |-> nil]} \* line 59 - ELSE {} <: {PrevoteT} \* else of line 58 - IN \* line 59, or else of 58 - msgsPrevote' = [msgsPrevote EXCEPT ![tm[2], tm[3]] = - msgsPrevote[tm[2], tm[3]] \cup newMsgs] - /\ UNCHANGED <> - -\* lines 61-64 -OnTimeoutPrevote(p) == - \E tm \in timeoutPrevote: \* a timeout occurs - /\ tm[1] = p - /\ timeoutPrevote' = timeoutPrevote \ {tm} \* remove from the future timeouts - /\ LET UpdateNeeded == tm[2] = h[p] /\ tm[3] = round[p] /\ step[p] = "PREVOTE" IN - /\ step' = - IF UpdateNeeded - THEN [step EXCEPT ![p] = "PRECOMMIT"] - ELSE step \* line 64 - /\ LET newMsgs == - IF UpdateNeeded - THEN {[src |-> tm[1], hash |-> nil]} \* line 63 - ELSE {} <: {PrecommitT} \* else of line 62 - IN \* line 63, or else of 62 - msgsPrecommit' = [msgsPrecommit EXCEPT ![tm[2], tm[3]] = - msgsPrecommit[tm[2], tm[3]] \cup newMsgs] - /\ UNCHANGED <> - -\* lines 65-67 -OnTimeoutPrecommitOutside(p) == - \E tm \in timeoutPrecommit: \* a timeout occurs - /\ tm[1] = p - /\ (tm[2] /= h[p] \/ tm[3] /= round[p]) \* but we are in another round or height - /\ timeoutPrecommit' = timeoutPrecommit \ {tm} \* remove from the future timeouts - /\ UNCHANGED <> - -\* lines 65-67 -OnTimeoutPrecommitInside(p) == - /\ round[p] + 1 \in Rounds - \* THIS IS NOT PART OF THE ORIGINAL ALGORITHM, BUT A SAFEGUARD TO PREVENT ROUNDS FROM OVERFLOWING - /\ <> \in timeoutPrecommit \* the timeout occurs for the current round and height - /\ timeoutPrecommit' = timeoutPrecommit \ {<>} \* remove from the future timeouts - /\ StartRound(p, h[p], round[p] + 1) - /\ UNCHANGED <> - - -Next == - \/ \E p \in Procs: - \/ UponProposalInPropose(p) - \/ UponProposalInProposeAndPrevote(p) - \/ UponPrevoteFirstTime(p) - \/ UponProposalInPrevoteOrCommitAndPrevote(p) - \/ UponPrevoteNil(p) \* FIXME: disabled for model checking - \/ UponPrecommitFirstTime(p) - \/ UponProposalInPrecommitNoDecision(p) - \/ UponCatchupRound(p) - \/ OnTimeoutPropose(p) - \/ OnTimeoutPrevote(p) - \/ OnTimeoutPrecommitOutside(p) - \/ OnTimeoutPrecommitInside(p) - \* a safeguard to prevent deadlocks when the algorithm goes to further heights or rounds - \*\/ UNCHANGED vars - -\* safety -Agreement == - \A p, q \in Procs, ht \in Heights: - \/ decision[p][ht] = nil - \/ decision[q][ht] = nil - \/ decision[p][ht] = decision[q][ht] - -\* simple reachability properties to make sure that the algorithm is doing anything useful -NoDecision == \A p \in Procs, ht \in Heights: decision[p][ht] = nil - -NoPrecommit == \A p \in Procs: step[p] /= "PRECOMMIT" - -NoTwoLockedValues == - \A p, q \in Procs: - h[p] = h[q] => lockedValue[p] = nil \/ lockedValue[q] = nil \/ lockedValue[p] = lockedValue[q] - -NoTwoLockedRounds == - \A p, q \in Procs: - h[p] = h[q] => lockedRound[p] = -1 \/ lockedRound[q] = -1 \/ lockedRound[p] = lockedRound[q] - - -============================================================================= -\* Modification History -\* Last modified Fri Mar 22 08:57:10 CET 2019 by igor -\* Created Fri Mar 15 10:30:17 CET 2019 by igor diff --git a/docs/spec/tendermint-fork/apalache-n4f1.properties b/docs/spec/tendermint-fork/apalache-n4f1.properties deleted file mode 100644 index c534db654..000000000 --- a/docs/spec/tendermint-fork/apalache-n4f1.properties +++ /dev/null @@ -1,7 +0,0 @@ -search.transitionFilter=0,11,9,0 -#search.invariantFilter=5|6 -#search.invariantFilter=1[5-9] -search.transition.timeout=7200 -search.invariant.timeout=7200 -#search.invariantFilter=[7-9]|1[0-7] -#search.learnFromUnsat=true diff --git a/docs/spec/tendermint-fork/apalache-n4f2.properties b/docs/spec/tendermint-fork/apalache-n4f2.properties deleted file mode 100644 index abde56385..000000000 --- a/docs/spec/tendermint-fork/apalache-n4f2.properties +++ /dev/null @@ -1,7 +0,0 @@ -#search.transitionFilter=0,11,9,0 -#search.invariantFilter=5|6 -#search.invariantFilter=1[5-9] -search.transition.timeout=7200 -search.invariant.timeout=7200 -#search.invariantFilter=[7-9]|1[0-7] -#search.learnFromUnsat=true diff --git a/docs/spec/tendermint-fork/apalache-n5f1.properties b/docs/spec/tendermint-fork/apalache-n5f1.properties deleted file mode 100644 index 596ae892e..000000000 --- a/docs/spec/tendermint-fork/apalache-n5f1.properties +++ /dev/null @@ -1,10 +0,0 @@ -x = [^02]|[1-2][0-9] -search.transitionFilter=0,11,11,9,9,0,${x},${x},${x},${x},${x},${x},${x} -#search.transitionFilter=0,11,11,9,9,0,${x},${x},${x},${x},${x},${x},${x} -#search.invariantFilter=5|6 -search.invariantFilter=1[3-9] -#search.invariantFilter=1[3-9] -search.transition.timeout=7200 -#search.invariant.timeout=7200 -#search.invariantFilter=[7-9]|1[0-7] -#search.learnFromUnsat=true diff --git a/docs/spec/tendermint-fork/apalache-n5f1T3.properties b/docs/spec/tendermint-fork/apalache-n5f1T3.properties deleted file mode 100644 index fd0dbef36..000000000 --- a/docs/spec/tendermint-fork/apalache-n5f1T3.properties +++ /dev/null @@ -1,9 +0,0 @@ -x = [^02]|[1-2][0-9] -search.transitionFilter=0,11,11,11,9,9,9,0,${x},${x},${x},${x},${x},${x},${x},${x},${x} -search.invariantFilter=1[7-9] -#search.transitionFilter=0,11,11,9,9,0,${x},${x},${x},${x},${x},${x},${x},${x} -#search.invariantFilter=5|6 -search.transition.timeout=7200 -#search.invariant.timeout=7200 -#search.invariantFilter=[7-9]|1[0-7] -#search.learnFromUnsat=true diff --git a/docs/spec/tendermint-fork/apalache.properties b/docs/spec/tendermint-fork/apalache.properties deleted file mode 100644 index 83d945372..000000000 --- a/docs/spec/tendermint-fork/apalache.properties +++ /dev/null @@ -1,7 +0,0 @@ -search.transitionFilter=0,11,11,9,9,0,0 -#search.invariantFilter=5|6 -#search.invariantFilter=1[5-9] -search.transition.timeout=7200 -search.invariant.timeout=7200 -#search.invariantFilter=[7-9]|1[0-7] -#search.learnFromUnsat=true From 78edaf9a6dbc2abdc5d2b427ba6aef0831a171b3 Mon Sep 17 00:00:00 2001 From: Igor Konnov Date: Tue, 4 Aug 2020 11:32:27 +0200 Subject: [PATCH 3/6] Update docs/spec/tendermint-fork-cases/TendermintAcc3.tla Co-authored-by: istoilkovska --- docs/spec/tendermint-fork-cases/TendermintAcc3.tla | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/spec/tendermint-fork-cases/TendermintAcc3.tla b/docs/spec/tendermint-fork-cases/TendermintAcc3.tla index 70826006e..bceb99df2 100644 --- a/docs/spec/tendermint-fork-cases/TendermintAcc3.tla +++ b/docs/spec/tendermint-fork-cases/TendermintAcc3.tla @@ -165,7 +165,7 @@ BroadcastProposal(pSrc, pRound, pProposal, pValidRound) == AsMsg([type |-> "PROPOSAL", src |-> pSrc, round |-> pRound, proposal |-> pProposal, validRound |-> pValidRound]) IN - msgsPropose' = [msgsPropose EXCEPT ![pRound] = msgsPropose[pRound] \cup {newMsg}] + msgsPropose' = [msgsPropose EXCEPT ![pRound] = msgsPropose[pRound] \union {newMsg}] BroadcastPrevote(pSrc, pRound, pId) == LET newMsg == AsMsg([type |-> "PREVOTE", From 2865598821ce04ebd090c4fc4c91b1dd381851aa Mon Sep 17 00:00:00 2001 From: Igor Konnov Date: Tue, 4 Aug 2020 11:32:56 +0200 Subject: [PATCH 4/6] Update docs/spec/tendermint-fork-cases/TendermintAcc3.tla Co-authored-by: istoilkovska --- docs/spec/tendermint-fork-cases/TendermintAcc3.tla | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/spec/tendermint-fork-cases/TendermintAcc3.tla b/docs/spec/tendermint-fork-cases/TendermintAcc3.tla index bceb99df2..c65ef6bac 100644 --- a/docs/spec/tendermint-fork-cases/TendermintAcc3.tla +++ b/docs/spec/tendermint-fork-cases/TendermintAcc3.tla @@ -171,7 +171,7 @@ BroadcastPrevote(pSrc, pRound, pId) == LET newMsg == AsMsg([type |-> "PREVOTE", src |-> pSrc, round |-> pRound, id |-> pId]) IN - msgsPrevote' = [msgsPrevote EXCEPT ![pRound] = msgsPrevote[pRound] \cup {newMsg}] + msgsPrevote' = [msgsPrevote EXCEPT ![pRound] = msgsPrevote[pRound] \union {newMsg}] BroadcastPrecommit(pSrc, pRound, pId) == LET newMsg == AsMsg([type |-> "PRECOMMIT", From 857c3763c3f21295ab6f0cda6f89711e3ee52ea5 Mon Sep 17 00:00:00 2001 From: Igor Konnov Date: Tue, 4 Aug 2020 11:33:07 +0200 Subject: [PATCH 5/6] Update docs/spec/tendermint-fork-cases/TendermintAcc3.tla Co-authored-by: istoilkovska --- docs/spec/tendermint-fork-cases/TendermintAcc3.tla | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/spec/tendermint-fork-cases/TendermintAcc3.tla b/docs/spec/tendermint-fork-cases/TendermintAcc3.tla index c65ef6bac..581969436 100644 --- a/docs/spec/tendermint-fork-cases/TendermintAcc3.tla +++ b/docs/spec/tendermint-fork-cases/TendermintAcc3.tla @@ -177,7 +177,7 @@ BroadcastPrecommit(pSrc, pRound, pId) == LET newMsg == AsMsg([type |-> "PRECOMMIT", src |-> pSrc, round |-> pRound, id |-> pId]) IN - msgsPrecommit' = [msgsPrecommit EXCEPT ![pRound] = msgsPrecommit[pRound] \cup {newMsg}] + msgsPrecommit' = [msgsPrecommit EXCEPT ![pRound] = msgsPrecommit[pRound] \union {newMsg}] (********************* PROTOCOL TRANSITIONS ******************************) From b49bd4c1385d2899271217b57951015f13b6c331 Mon Sep 17 00:00:00 2001 From: Igor Konnov Date: Thu, 24 Sep 2020 15:16:13 +0200 Subject: [PATCH 6/6] added the missing report files --- .../results/001indinv-apalache-card.csv | 31 + .../results/001indinv-apalache-mem-log.svg | 1285 ++++++++++++++++ .../results/001indinv-apalache-mem.svg | 1216 +++++++++++++++ .../results/001indinv-apalache-ncells.svg | 1227 +++++++++++++++ .../results/001indinv-apalache-nclauses.svg | 1197 +++++++++++++++ .../results/001indinv-apalache-report.md | 133 ++ .../results/001indinv-apalache-time-log.svg | 1354 +++++++++++++++++ .../results/001indinv-apalache-time.svg | 1094 +++++++++++++ .../results/001indinv-apalache-unstable.csv | 31 + 9 files changed, 7568 insertions(+) create mode 100644 docs/spec/tendermint-fork-cases/results/001indinv-apalache-card.csv create mode 100644 docs/spec/tendermint-fork-cases/results/001indinv-apalache-mem-log.svg create mode 100644 docs/spec/tendermint-fork-cases/results/001indinv-apalache-mem.svg create mode 100644 docs/spec/tendermint-fork-cases/results/001indinv-apalache-ncells.svg create mode 100644 docs/spec/tendermint-fork-cases/results/001indinv-apalache-nclauses.svg create mode 100644 docs/spec/tendermint-fork-cases/results/001indinv-apalache-report.md create mode 100644 docs/spec/tendermint-fork-cases/results/001indinv-apalache-time-log.svg create mode 100644 docs/spec/tendermint-fork-cases/results/001indinv-apalache-time.svg create mode 100644 docs/spec/tendermint-fork-cases/results/001indinv-apalache-unstable.csv diff --git a/docs/spec/tendermint-fork-cases/results/001indinv-apalache-card.csv b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-card.csv new file mode 100644 index 000000000..9af2d80d7 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-card.csv @@ -0,0 +1,31 @@ +01:no,02:tool,03:status,04:time_sec,05:depth,05:mem_kb,10:ninit_trans,11:ninit_trans,12:ncells,13:nclauses,14:navg_clause_len +1,apalache,NoError,757,1,6689920,0,0,255850,2916339,20 +2,apalache,NoError,715,1,7178440,0,0,241134,2878496,21 +3,apalache,NoError,580,1,7177956,0,0,227772,2854964,21 +4,apalache,NoError,1492,1,10086952,0,0,346159,4446361,21 +5,apalache,NoError,1258,1,10645452,0,0,329305,4393688,21 +6,apalache,NoError,3344,1,13707364,0,0,560069,9236533,20 +7,apalache,NoError,3288,1,13834196,0,0,531012,9216485,21 +8,apalache,NoError,2927,1,13611468,0,0,508797,9012976,21 +9,apalache,NoError,11050,1,17577780,0,0,1002795,20568977,20 +10,apalache,NoError,9356,1,17517792,0,0,940114,20062564,20 +11,apalache,NoError,286,0,4137892,0,0,148963,2161260,17 +12,apalache,NoError,849,0,17076088,0,0,2789102,8311118,10 +13,apalache,NoError,1435,0,23125812,0,0,6317013,16529247,10 +14,apalache,NoError,468,0,5417264,0,0,212357,3324811,17 +15,apalache,NoError,1397,0,21924168,0,0,4326480,12872129,10 +16,apalache,NoError,1242,0,9435876,0,0,374517,7397022,16 +17,apalache,Fail,2612,0,27951008,0,0,172254,3647560,17 +18,apalache,Fail,2625,0,28354920,0,0,160287,3600511,17 +19,apalache,NoError,3172,0,16896056,0,0,734069,17072460,16 +20,apalache,Fail,3873,0,30181108,0,0,341439,8450107,16 +21,apalache,NoError,12,0,594592,0,0,5622,33845,23 +22,apalache,NoError,17,0,860608,0,0,9690,68116,23 +23,apalache,NoError,25,0,1062868,0,0,12757,104964,22 +24,apalache,NoError,13,0,766340,0,0,5784,36940,25 +25,apalache,NoError,20,0,810136,0,0,9852,73824,25 +26,apalache,NoError,24,0,1034140,0,0,10220,85339,28 +27,apalache,NoError,33,0,1105020,0,0,14267,131054,28 +28,apalache,NoError,44,0,1365304,0,0,18352,180731,27 +29,apalache,NoError,45,0,1349440,0,0,14797,155936,32 +30,apalache,NoError,55,0,1755904,0,0,18844,213416,31 diff --git a/docs/spec/tendermint-fork-cases/results/001indinv-apalache-mem-log.svg b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-mem-log.svg new file mode 100644 index 000000000..9864b562d --- /dev/null +++ b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-mem-log.svg @@ -0,0 +1,1285 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/spec/tendermint-fork-cases/results/001indinv-apalache-mem.svg b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-mem.svg new file mode 100644 index 000000000..b4b5b4b8c --- /dev/null +++ b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-mem.svg @@ -0,0 +1,1216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/spec/tendermint-fork-cases/results/001indinv-apalache-ncells.svg b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-ncells.svg new file mode 100644 index 000000000..184a5f809 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-ncells.svg @@ -0,0 +1,1227 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/spec/tendermint-fork-cases/results/001indinv-apalache-nclauses.svg b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-nclauses.svg new file mode 100644 index 000000000..67e655fa9 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-nclauses.svg @@ -0,0 +1,1197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/spec/tendermint-fork-cases/results/001indinv-apalache-report.md b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-report.md new file mode 100644 index 000000000..5bad2b0c7 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-report.md @@ -0,0 +1,133 @@ +# Results of 001indinv-apalache + + +## 1. Awesome plots + +### 1.1. Time (logarithmic scale) + +![time-log](001indinv-apalache-time-log.svg "Time Log") + +### 1.2. Time (linear) + +![time-log](001indinv-apalache-time.svg "Time Log") + +### 1.3. Memory (logarithmic scale) + +![mem-log](001indinv-apalache-mem-log.svg "Memory Log") + +### 1.4. Memory (linear) + +![mem](001indinv-apalache-mem.svg "Memory Log") + +### 1.5. Number of arena cells (linear) + +![ncells](001indinv-apalache-ncells.svg "Number of arena cells") + +### 1.6. Number of SMT clauses (linear) + +![nclauses](001indinv-apalache-nclauses.svg "Number of SMT clauses") + +## 2. Input parameters + +no | filename | tool | timeout | init | inv | next | args +----|-----------------|------------|-----------|------------|------------------------------------|--------|------------------------------ +1 | MC_n4_f1.tla | apalache | 10h | TypedInv | TypedInv | | --length=1 --cinit=ConstInit +2 | MC_n4_f2.tla | apalache | 10h | TypedInv | TypedInv | | --length=1 --cinit=ConstInit +3 | MC_n4_f3.tla | apalache | 10h | TypedInv | TypedInv | | --length=1 --cinit=ConstInit +4 | MC_n5_f1.tla | apalache | 10h | TypedInv | TypedInv | | --length=1 --cinit=ConstInit +5 | MC_n5_f2.tla | apalache | 10h | TypedInv | TypedInv | | --length=1 --cinit=ConstInit +6 | MC_n7_f2.tla | apalache | 10h | TypedInv | TypedInv | | --length=1 --cinit=ConstInit +7 | MC_n7_f3.tla | apalache | 10h | TypedInv | TypedInv | | --length=1 --cinit=ConstInit +8 | MC_n7_f4.tla | apalache | 10h | TypedInv | TypedInv | | --length=1 --cinit=ConstInit +9 | MC_n10_f3.tla | apalache | 24h | TypedInv | TypedInv | | --length=1 --cinit=ConstInit +10 | MC_n10_f4.tla | apalache | 24h | TypedInv | TypedInv | | --length=1 --cinit=ConstInit +11 | MC_n4_f1.tla | apalache | 10h | TypedInv | Agreement | | --length=0 --cinit=ConstInit +12 | MC_n4_f2.tla | apalache | 10h | TypedInv | AgreementOrEquivocationOrAmnesia | | --length=0 --cinit=ConstInit +13 | MC_n4_f3.tla | apalache | 10h | TypedInv | AgreementOrEquivocationOrAmnesia | | --length=0 --cinit=ConstInit +14 | MC_n5_f1.tla | apalache | 10h | TypedInv | Agreement | | --length=0 --cinit=ConstInit +15 | MC_n5_f2.tla | apalache | 10h | TypedInv | AgreementOrEquivocationOrAmnesia | | --length=0 --cinit=ConstInit +16 | MC_n7_f2.tla | apalache | 10h | TypedInv | Agreement | | --length=0 --cinit=ConstInit +17 | MC_n7_f3.tla | apalache | 10h | TypedInv | AgreementOrEquivocationOrAmnesia | | --length=0 --cinit=ConstInit +18 | MC_n7_f4.tla | apalache | 10h | TypedInv | AgreementOrEquivocationOrAmnesia | | --length=0 --cinit=ConstInit +19 | MC_n10_f3.tla | apalache | 24h | TypedInv | Agreement | | --length=0 --cinit=ConstInit +20 | MC_n10_f4.tla | apalache | 24h | TypedInv | AgreementOrEquivocationOrAmnesia | | --length=0 --cinit=ConstInit +21 | MC_n4_f1.tla | apalache | 10h | Init | TypedInv | | --length=0 --cinit=ConstInit +22 | MC_n4_f2.tla | apalache | 10h | Init | TypedInv | | --length=0 --cinit=ConstInit +23 | MC_n4_f3.tla | apalache | 10h | Init | TypedInv | | --length=0 --cinit=ConstInit +24 | MC_n5_f1.tla | apalache | 10h | Init | TypedInv | | --length=0 --cinit=ConstInit +25 | MC_n5_f2.tla | apalache | 10h | Init | TypedInv | | --length=0 --cinit=ConstInit +26 | MC_n7_f2.tla | apalache | 10h | Init | TypedInv | | --length=0 --cinit=ConstInit +27 | MC_n7_f3.tla | apalache | 10h | Init | TypedInv | | --length=0 --cinit=ConstInit +28 | MC_n7_f4.tla | apalache | 10h | Init | TypedInv | | --length=0 --cinit=ConstInit +29 | MC_n10_f3.tla | apalache | 24h | Init | TypedInv | | --length=0 --cinit=ConstInit +30 | MC_n10_f4.tla | apalache | 24h | Init | TypedInv | | --length=0 --cinit=ConstInit + +## 3. Detailed results: 001indinv-apalache-unstable.csv + +01:no | 02:tool | 03:status | 04:time_sec | 05:depth | 05:mem_kb | 10:ninit_trans | 11:ninit_trans | 12:ncells | 13:nclauses | 14:navg_clause_len +-------|------------|-------------|---------------|------------|-------------|------------------|------------------|-------------|---------------|-------------------- +1 | apalache | NoError | 21m | 1 | 8.0GB | 0 | 0 | 330K | 2.0M | 25 +2 | apalache | NoError | 20m | 1 | 8.0GB | 0 | 0 | 313K | 2.0M | 25 +3 | apalache | NoError | 19m | 1 | 7.0GB | 0 | 0 | 299K | 2.0M | 25 +4 | apalache | NoError | 39m | 1 | 11GB | 0 | 0 | 461K | 3.0M | 26 +5 | apalache | NoError | 40m | 1 | 11GB | 0 | 0 | 445K | 3.0M | 27 +6 | apalache | NoError | 2h02m | 1 | 14GB | 0 | 0 | 780K | 6.0M | 28 +7 | apalache | NoError | 2h02m | 1 | 14GB | 0 | 0 | 754K | 6.0M | 29 +8 | apalache | NoError | 2h02m | 1 | 14GB | 0 | 0 | 728K | 6.0M | 29 +9 | apalache | NoError | 11h | 1 | 20GB | 0 | 0 | 1.0M | 13M | 31 +10 | apalache | NoError | 11h | 1 | 20GB | 0 | 0 | 1.0M | 13M | 32 +11 | apalache | NoError | 6m06s | 0 | 5.0GB | 0 | 0 | 219K | 1.0M | 20 +12 | apalache | NoError | 17m | 0 | 17GB | 0 | 0 | 2.0M | 7.0M | 11 +13 | apalache | NoError | 25m | 0 | 22GB | 0 | 0 | 6.0M | 15M | 10 +14 | apalache | NoError | 11m | 0 | 7.0GB | 0 | 0 | 326K | 2.0M | 22 +15 | apalache | NoError | 31m | 0 | 21GB | 0 | 0 | 4.0M | 12M | 11 +16 | apalache | NoError | 39m | 0 | 13GB | 0 | 0 | 592K | 5.0M | 24 +17 | apalache | Fail | 1h01m | 0 | 27GB | 0 | 0 | 280K | 2.0M | 24 +18 | apalache | Fail | 1h01m | 0 | 27GB | 0 | 0 | 268K | 2.0M | 24 +19 | apalache | NoError | 2h02m | 0 | 19GB | 0 | 0 | 1.0M | 10M | 27 +20 | apalache | Fail | 2h02m | 0 | 30GB | 0 | 0 | 564K | 4.0M | 28 +21 | apalache | NoError | 12s | 0 | 588MB | 0 | 0 | 5.0K | 33K | 23 +22 | apalache | NoError | 18s | 0 | 816MB | 0 | 0 | 9.0K | 67K | 23 +23 | apalache | NoError | 25s | 0 | 937MB | 0 | 0 | 12K | 103K | 22 +24 | apalache | NoError | 13s | 0 | 776MB | 0 | 0 | 5.0K | 36K | 25 +25 | apalache | NoError | 19s | 0 | 807MB | 0 | 0 | 9.0K | 73K | 25 +26 | apalache | NoError | 23s | 0 | 976MB | 0 | 0 | 10K | 84K | 29 +27 | apalache | NoError | 34s | 0 | 1.0GB | 0 | 0 | 14K | 129K | 28 +28 | apalache | NoError | 42s | 0 | 1.0GB | 0 | 0 | 18K | 179K | 27 +29 | apalache | NoError | 43s | 0 | 1.0GB | 0 | 0 | 14K | 154K | 32 +30 | apalache | NoError | 59s | 0 | 1.0GB | 0 | 0 | 18K | 211K | 31 + +## 4. Detailed results: 001indinv-apalache-card.csv + +01:no | 02:tool | 03:status | 04:time_sec | 05:depth | 05:mem_kb | 10:ninit_trans | 11:ninit_trans | 12:ncells | 13:nclauses | 14:navg_clause_len +-------|------------|-------------|---------------|------------|-------------|------------------|------------------|-------------|---------------|-------------------- +1 | apalache | NoError | 12m | 1 | 6.0GB | 0 | 0 | 255K | 2.0M | 20 +2 | apalache | NoError | 11m | 1 | 6.0GB | 0 | 0 | 241K | 2.0M | 21 +3 | apalache | NoError | 9m09s | 1 | 6.0GB | 0 | 0 | 227K | 2.0M | 21 +4 | apalache | NoError | 24m | 1 | 9.0GB | 0 | 0 | 346K | 4.0M | 21 +5 | apalache | NoError | 20m | 1 | 10GB | 0 | 0 | 329K | 4.0M | 21 +6 | apalache | NoError | 55m | 1 | 13GB | 0 | 0 | 560K | 9.0M | 20 +7 | apalache | NoError | 54m | 1 | 13GB | 0 | 0 | 531K | 9.0M | 21 +8 | apalache | NoError | 48m | 1 | 12GB | 0 | 0 | 508K | 9.0M | 21 +9 | apalache | NoError | 3h03m | 1 | 16GB | 0 | 0 | 1.0M | 20M | 20 +10 | apalache | NoError | 2h02m | 1 | 16GB | 0 | 0 | 940K | 20M | 20 +11 | apalache | NoError | 4m04s | 0 | 3.0GB | 0 | 0 | 148K | 2.0M | 17 +12 | apalache | NoError | 14m | 0 | 16GB | 0 | 0 | 2.0M | 8.0M | 10 +13 | apalache | NoError | 23m | 0 | 22GB | 0 | 0 | 6.0M | 16M | 10 +14 | apalache | NoError | 7m07s | 0 | 5.0GB | 0 | 0 | 212K | 3.0M | 17 +15 | apalache | NoError | 23m | 0 | 20GB | 0 | 0 | 4.0M | 12M | 10 +16 | apalache | NoError | 20m | 0 | 8.0GB | 0 | 0 | 374K | 7.0M | 16 +17 | apalache | Fail | 43m | 0 | 26GB | 0 | 0 | 172K | 3.0M | 17 +18 | apalache | Fail | 43m | 0 | 27GB | 0 | 0 | 160K | 3.0M | 17 +19 | apalache | NoError | 52m | 0 | 16GB | 0 | 0 | 734K | 17M | 16 +20 | apalache | Fail | 1h01m | 0 | 28GB | 0 | 0 | 341K | 8.0M | 16 +21 | apalache | NoError | 12s | 0 | 580MB | 0 | 0 | 5.0K | 33K | 23 +22 | apalache | NoError | 17s | 0 | 840MB | 0 | 0 | 9.0K | 68K | 23 +23 | apalache | NoError | 25s | 0 | 1.0GB | 0 | 0 | 12K | 104K | 22 +24 | apalache | NoError | 13s | 0 | 748MB | 0 | 0 | 5.0K | 36K | 25 +25 | apalache | NoError | 20s | 0 | 791MB | 0 | 0 | 9.0K | 73K | 25 +26 | apalache | NoError | 24s | 0 | 1009MB | 0 | 0 | 10K | 85K | 28 +27 | apalache | NoError | 33s | 0 | 1.0GB | 0 | 0 | 14K | 131K | 28 +28 | apalache | NoError | 44s | 0 | 1.0GB | 0 | 0 | 18K | 180K | 27 +29 | apalache | NoError | 45s | 0 | 1.0GB | 0 | 0 | 14K | 155K | 32 +30 | apalache | NoError | 55s | 0 | 1.0GB | 0 | 0 | 18K | 213K | 31 diff --git a/docs/spec/tendermint-fork-cases/results/001indinv-apalache-time-log.svg b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-time-log.svg new file mode 100644 index 000000000..b4d69bab9 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-time-log.svg @@ -0,0 +1,1354 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/spec/tendermint-fork-cases/results/001indinv-apalache-time.svg b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-time.svg new file mode 100644 index 000000000..20d5e1a8b --- /dev/null +++ b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-time.svg @@ -0,0 +1,1094 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/spec/tendermint-fork-cases/results/001indinv-apalache-unstable.csv b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-unstable.csv new file mode 100644 index 000000000..7d46072d8 --- /dev/null +++ b/docs/spec/tendermint-fork-cases/results/001indinv-apalache-unstable.csv @@ -0,0 +1,31 @@ +01:no,02:tool,03:status,04:time_sec,05:depth,05:mem_kb,10:ninit_trans,11:ninit_trans,12:ncells,13:nclauses,14:navg_clause_len +1,apalache,NoError,1301,1,8497892,0,0,330488,2507123,25 +2,apalache,NoError,1225,1,8787920,0,0,313983,2424451,25 +3,apalache,NoError,1146,1,8284308,0,0,299480,2379006,25 +4,apalache,NoError,2391,1,12547740,0,0,461690,3765633,26 +5,apalache,NoError,2450,1,12471680,0,0,445753,3695822,27 +6,apalache,NoError,9971,1,15420532,0,0,780909,6900742,28 +7,apalache,NoError,9698,1,15702048,0,0,754742,6931775,29 +8,apalache,NoError,9300,1,15049568,0,0,728499,6679564,29 +9,apalache,NoError,42307,1,21681092,0,0,1451761,13556928,31 +10,apalache,NoError,41464,1,21471424,0,0,1391910,13310244,32 +11,apalache,NoError,398,0,5541800,0,0,219433,1722072,20 +12,apalache,NoError,1071,0,18618796,0,0,2868158,7817870,11 +13,apalache,NoError,1528,0,23933300,0,0,6407571,15963579,10 +14,apalache,NoError,694,0,8226532,0,0,326597,2646451,22 +15,apalache,NoError,1864,0,22907328,0,0,4451850,12126989,11 +16,apalache,NoError,2377,0,14444576,0,0,592163,5025992,24 +17,apalache,Fail,3738,0,28982004,0,0,280934,2463612,24 +18,apalache,Fail,3721,0,28828436,0,0,268824,2418130,24 +19,apalache,NoError,9216,0,20139480,0,0,1179739,10135524,27 +20,apalache,Fail,9712,0,31466408,0,0,564069,4984843,28 +21,apalache,NoError,12,0,602944,0,0,5649,33693,23 +22,apalache,NoError,18,0,836080,0,0,9739,67569,23 +23,apalache,NoError,25,0,959564,0,0,12833,103994,22 +24,apalache,NoError,13,0,795316,0,0,5812,36807,25 +25,apalache,NoError,19,0,826572,0,0,9902,73287,25 +26,apalache,NoError,23,0,999580,0,0,10267,84711,29 +27,apalache,NoError,34,0,1133032,0,0,14341,129922,28 +28,apalache,NoError,42,0,1319784,0,0,18453,179014,27 +29,apalache,NoError,43,0,1334480,0,0,14868,154666,32 +30,apalache,NoError,59,0,1575408,0,0,18942,211480,31