From 27af4a218f0ef8277012df4b6f6490b15932da6c Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Fri, 23 Aug 2019 09:57:24 -0600 Subject: [PATCH 01/66] Update .gitignore --- .gitignore | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 75821e0..a369690 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,11 @@ # The tla+ toolbox creates a .toolbox folder for each specification you create # While this folder does contain model details, which we potentially want to check # in, it also contains a lot of other files, so we ignore it for the moment -*.toolbox/ \ No newline at end of file +*.toolbox/ + +# The tlatex utility produces auxilliary files when compiling the spec +*.aux +*.dvi +*.log +*.old +*.tex \ No newline at end of file From 2d5b1c3c3192931e4025a11342d6a14bf4e21374 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Fri, 23 Aug 2019 15:46:12 -0600 Subject: [PATCH 02/66] wip --- ForceMove/ForceMove.tla | 219 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 ForceMove/ForceMove.tla diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla new file mode 100644 index 0000000..f0a3f24 --- /dev/null +++ b/ForceMove/ForceMove.tla @@ -0,0 +1,219 @@ +----------------------------- MODULE ForceMove ----------------------------- +EXTENDS Integers, Sequences, FiniteSets, TLC +CONSTANTS + Alice, \* A model value + OtherParticipants, \* A set of model values + NumHistories + +ChallengeStatus == [ + CLEARED |-> "CLEARED", + ACTIVE |-> "ACTIVE", + EXPIRED |-> "EXPIRED" +] + +Range(f) == { f[x] : x \in DOMAIN f } +StartingTurnNumber == 1 + +ASSUME + /\ Alice \notin OtherParticipants + /\ Cardinality(OtherParticipants) > 0 + /\ NumHistories \in Nat + +(* --algorithm consensus_update +\* This is Pluscal (Pascal for TLA+) + +variables challenge = [turnNumber |-> 0, status |-> ChallengeStatus.CLEARED, votesRequired |-> 0] + +define +\* Arrays are 1-indexed, while the % operator returns a number between 0 and NumParticipants. +\* This explains the following slightly complicated expression +mover(turnNumber) == 1 + ((turnNumber-1) % NumParticipants) +challengeIsPresent == challenge.status # ChallengeStatus.CLEARED +end define; + +macro forceMove(turnNumber, votesRequired) +begin +challenge := [ + turnNumber |-> turnNumber, + status |-> ChallengeStatus.ACTIVE, + votesRequired |-> votesRequired +]; + +end macro; + +macro processChallenge() +begin skip; end macro; + +macro respondToChallenge() +begin +skip; +end macro; + +fair process adjudicator = 0 +begin +(***************************************************************************) +(* This process expires challenges. *) +(***************************************************************************) +HandleChallenge: +while challenge.status # ChallengeStatus.EXPIRED +do + await challenge.status = ChallengeStatus.ACTIVE; + ExpireChallenge: + challenge := [ status |-> ChallengeStatus.EXPIRED ] @@ challenge; +end while; +end process; + +fair process alice = 1 +begin +(***************************************************************************) +(* Alice has commitments (n - numParticipants)..(n-1). She wants to end *) +(* up with commitments (n - numParticipants + 1)..n. She is allowed to: *) +(* - Call forceMove with any states that she currently has *) +(* - Call refute with any state that she has *) +(* - Call respondWithMove whenever there's an active challenge forcing *) +(* her to move *) +(***************************************************************************) +HandleChallenge: +while challenge.status # ChallengeStatus.EXPIRED +do + await challenge.status = ChallengeStatus.ACTIVE; + ExpireChallenge: + challenge := [ status |-> ChallengeStatus.EXPIRED ] @@ challenge; +end while; +end process; + +fair process eve = 2 +begin +(**************************************************************************** +Eve can do almost anything. She has k different histories that each +contain commitments 1...(n-1). She can sign any data with any private +key other than Alice's. She can call any adjudicator function, at any +time. She can front-run any transaction an arbitrary number of times -- ie. if anyone else calls an adjudicator function, she can then choose to call +****************************************************************************) +HandleChallenge: +while challenge.status # ChallengeStatus.EXPIRED +do + await challenge.status = ChallengeStatus.ACTIVE; + ExpireChallenge: + challenge := [ status |-> ChallengeStatus.EXPIRED ] @@ challenge; +end while; +end process; + + +end algorithm; +*) + + +\* BEGIN TRANSLATION +\* Label HandleChallenge of process adjudicator at line 56 col 1 changed to HandleChallenge_ +\* Label ExpireChallenge of process adjudicator at line 60 col 9 changed to ExpireChallenge_ +\* Label HandleChallenge of process alice at line 75 col 1 changed to HandleChallenge_a +\* Label ExpireChallenge of process alice at line 79 col 9 changed to ExpireChallenge_a +VARIABLES challenge, pc + +(* define statement *) +mover(turnNumber) == 1 + ((turnNumber-1) % NumParticipants) +challengeIsPresent == challenge.status # ChallengeStatus.CLEARED + + +vars == << challenge, pc >> + +ProcSet == {0} \cup {1} \cup {2} + +Init == (* Global variables *) + /\ challenge = [turnNumber |-> 0, status |-> ChallengeStatus.CLEARED, votesRequired |-> 0] + /\ pc = [self \in ProcSet |-> CASE self = 0 -> "HandleChallenge_" + [] self = 1 -> "HandleChallenge_a" + [] self = 2 -> "HandleChallenge"] + +HandleChallenge_ == /\ pc[0] = "HandleChallenge_" + /\ IF challenge.status # ChallengeStatus.EXPIRED + THEN /\ challenge.status = ChallengeStatus.ACTIVE + /\ pc' = [pc EXCEPT ![0] = "ExpireChallenge_"] + ELSE /\ pc' = [pc EXCEPT ![0] = "Done"] + /\ UNCHANGED challenge + +ExpireChallenge_ == /\ pc[0] = "ExpireChallenge_" + /\ challenge' = [ status |-> ChallengeStatus.EXPIRED ] @@ challenge + /\ pc' = [pc EXCEPT ![0] = "HandleChallenge_"] + +adjudicator == HandleChallenge_ \/ ExpireChallenge_ + +HandleChallenge_a == /\ pc[1] = "HandleChallenge_a" + /\ IF challenge.status # ChallengeStatus.EXPIRED + THEN /\ challenge.status = ChallengeStatus.ACTIVE + /\ pc' = [pc EXCEPT ![1] = "ExpireChallenge_a"] + ELSE /\ pc' = [pc EXCEPT ![1] = "Done"] + /\ UNCHANGED challenge + +ExpireChallenge_a == /\ pc[1] = "ExpireChallenge_a" + /\ challenge' = [ status |-> ChallengeStatus.EXPIRED ] @@ challenge + /\ pc' = [pc EXCEPT ![1] = "HandleChallenge_a"] + +alice == HandleChallenge_a \/ ExpireChallenge_a + +HandleChallenge == /\ pc[2] = "HandleChallenge" + /\ IF challenge.status # ChallengeStatus.EXPIRED + THEN /\ challenge.status = ChallengeStatus.ACTIVE + /\ pc' = [pc EXCEPT ![2] = "ExpireChallenge"] + ELSE /\ pc' = [pc EXCEPT ![2] = "Done"] + /\ UNCHANGED challenge + +ExpireChallenge == /\ pc[2] = "ExpireChallenge" + /\ challenge' = [ status |-> ChallengeStatus.EXPIRED ] @@ challenge + /\ pc' = [pc EXCEPT ![2] = "HandleChallenge"] + +eve == HandleChallenge \/ ExpireChallenge + +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + +Next == adjudicator \/ alice \/ eve + \/ Terminating + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(adjudicator) + /\ WF_vars(alice) + /\ WF_vars(eve) + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +\* END TRANSLATION + +AllowedTurnNumbers == 0..(StartingTurnNumber + NumParticipants) +AllowedChallenges == + [ + turnNumber: AllowedTurnNumbers, + status: Range(ChallengeStatus), + votesRequired: 0..(NumParticipants - 1) + ] + + +\* Safety properties + +TypeOK == + /\ challenge \in AllowedChallenges + +\* TODO: Get TurnNumberDoesNotDecrease and StaysTerminated +\* For some reason, state[p].turnNumber' is not valid +\*TurnNumberDoesNotDecrease == +\* /\ \A p \in ParticipantIndices: state[p].turnNumber' >= state[p].turnNumber + +\* Once a process has terminated, its state does not change. +\*StaysTerminated == \A p \in ParticipantIndices: (Terminated(state[p]) => (state'[p] = state[p])) + +\* Liveness properties +\*ProtocolTerminatesWhenChallengeDoesNotExpire == +\* \/ <>[]( /\ challenge.status = ChallengeStatus.EXPIRED +\* /\ \E p \in ParticipantIndices: state[p].type = Types.TERMINATED) +\* \/ (\A p \in ParticipantIndices: <>[](/\ state[p].type = Types.SUCCESS +\* /\ state[p].turnNumber = StartingTurnNumber + NumParticipants)) +\* \/ (\A p \in ParticipantIndices: <>[](/\ state[p].type = Types.ABORTED +\* /\ state[p].turnNumber = state[1].turnNumber)) + + +============================================================================= +\* Modification History +\* Last modified Fri Aug 23 15:44:30 MDT 2019 by andrewstewart +\* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 2271340a2e99ae67d684a59d69ed6b384d776977 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Fri, 23 Aug 2019 15:54:27 -0600 Subject: [PATCH 03/66] wip --- ForceMove/ForceMove.tla | 55 +++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index f0a3f24..15768a7 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -2,8 +2,10 @@ EXTENDS Integers, Sequences, FiniteSets, TLC CONSTANTS Alice, \* A model value - OtherParticipants, \* A set of model values - NumHistories + Names, \* A set of model values + Participants, \* A set of model values + NumHistories, + NULL \* A model value representing null. ChallengeStatus == [ CLEARED |-> "CLEARED", @@ -13,20 +15,22 @@ ChallengeStatus == [ Range(f) == { f[x] : x \in DOMAIN f } StartingTurnNumber == 1 +NumParticipants == Len(Participants) ASSUME - /\ Alice \notin OtherParticipants - /\ Cardinality(OtherParticipants) > 0 + /\ Alice \in Names + /\ Cardinality(Names) = NumParticipants + /\ Len(Participants) >= 2 /\ NumHistories \in Nat + /\ \A p \in Range(Participants) : p \in Names -(* --algorithm consensus_update -\* This is Pluscal (Pascal for TLA+) +(* --algorithm forceMove -variables challenge = [turnNumber |-> 0, status |-> ChallengeStatus.CLEARED, votesRequired |-> 0] +variables + challenge = [turnNumber |-> 0, challengeStatus |-> ChallengeStatus.CLEARED], + submittedChallenge = NULL define -\* Arrays are 1-indexed, while the % operator returns a number between 0 and NumParticipants. -\* This explains the following slightly complicated expression mover(turnNumber) == 1 + ((turnNumber-1) % NumParticipants) challengeIsPresent == challenge.status # ChallengeStatus.CLEARED end define; @@ -105,23 +109,24 @@ end algorithm; \* BEGIN TRANSLATION -\* Label HandleChallenge of process adjudicator at line 56 col 1 changed to HandleChallenge_ -\* Label ExpireChallenge of process adjudicator at line 60 col 9 changed to ExpireChallenge_ -\* Label HandleChallenge of process alice at line 75 col 1 changed to HandleChallenge_a -\* Label ExpireChallenge of process alice at line 79 col 9 changed to ExpireChallenge_a -VARIABLES challenge, pc +\* Label HandleChallenge of process adjudicator at line 62 col 1 changed to HandleChallenge_ +\* Label ExpireChallenge of process adjudicator at line 66 col 9 changed to ExpireChallenge_ +\* Label HandleChallenge of process alice at line 81 col 1 changed to HandleChallenge_a +\* Label ExpireChallenge of process alice at line 85 col 9 changed to ExpireChallenge_a +VARIABLES challenge, submittedChallenge, pc (* define statement *) mover(turnNumber) == 1 + ((turnNumber-1) % NumParticipants) challengeIsPresent == challenge.status # ChallengeStatus.CLEARED -vars == << challenge, pc >> +vars == << challenge, submittedChallenge, pc >> ProcSet == {0} \cup {1} \cup {2} Init == (* Global variables *) - /\ challenge = [turnNumber |-> 0, status |-> ChallengeStatus.CLEARED, votesRequired |-> 0] + /\ challenge = [turnNumber |-> 0, challengeStatus |-> ChallengeStatus.CLEARED] + /\ submittedChallenge = NULL /\ pc = [self \in ProcSet |-> CASE self = 0 -> "HandleChallenge_" [] self = 1 -> "HandleChallenge_a" [] self = 2 -> "HandleChallenge"] @@ -131,11 +136,12 @@ HandleChallenge_ == /\ pc[0] = "HandleChallenge_" THEN /\ challenge.status = ChallengeStatus.ACTIVE /\ pc' = [pc EXCEPT ![0] = "ExpireChallenge_"] ELSE /\ pc' = [pc EXCEPT ![0] = "Done"] - /\ UNCHANGED challenge + /\ UNCHANGED << challenge, submittedChallenge >> ExpireChallenge_ == /\ pc[0] = "ExpireChallenge_" /\ challenge' = [ status |-> ChallengeStatus.EXPIRED ] @@ challenge /\ pc' = [pc EXCEPT ![0] = "HandleChallenge_"] + /\ UNCHANGED submittedChallenge adjudicator == HandleChallenge_ \/ ExpireChallenge_ @@ -144,11 +150,12 @@ HandleChallenge_a == /\ pc[1] = "HandleChallenge_a" THEN /\ challenge.status = ChallengeStatus.ACTIVE /\ pc' = [pc EXCEPT ![1] = "ExpireChallenge_a"] ELSE /\ pc' = [pc EXCEPT ![1] = "Done"] - /\ UNCHANGED challenge + /\ UNCHANGED << challenge, submittedChallenge >> ExpireChallenge_a == /\ pc[1] = "ExpireChallenge_a" /\ challenge' = [ status |-> ChallengeStatus.EXPIRED ] @@ challenge /\ pc' = [pc EXCEPT ![1] = "HandleChallenge_a"] + /\ UNCHANGED submittedChallenge alice == HandleChallenge_a \/ ExpireChallenge_a @@ -157,11 +164,12 @@ HandleChallenge == /\ pc[2] = "HandleChallenge" THEN /\ challenge.status = ChallengeStatus.ACTIVE /\ pc' = [pc EXCEPT ![2] = "ExpireChallenge"] ELSE /\ pc' = [pc EXCEPT ![2] = "Done"] - /\ UNCHANGED challenge + /\ UNCHANGED << challenge, submittedChallenge >> ExpireChallenge == /\ pc[2] = "ExpireChallenge" /\ challenge' = [ status |-> ChallengeStatus.EXPIRED ] @@ challenge /\ pc' = [pc EXCEPT ![2] = "HandleChallenge"] + /\ UNCHANGED submittedChallenge eve == HandleChallenge \/ ExpireChallenge @@ -185,15 +193,14 @@ AllowedTurnNumbers == 0..(StartingTurnNumber + NumParticipants) AllowedChallenges == [ turnNumber: AllowedTurnNumbers, - status: Range(ChallengeStatus), - votesRequired: 0..(NumParticipants - 1) + status: Range(ChallengeStatus) ] \* Safety properties -TypeOK == - /\ challenge \in AllowedChallenges +\*TypeOK == +\* /\ challenge \in AllowedChallenges \* TODO: Get TurnNumberDoesNotDecrease and StaysTerminated \* For some reason, state[p].turnNumber' is not valid @@ -215,5 +222,5 @@ TypeOK == ============================================================================= \* Modification History -\* Last modified Fri Aug 23 15:44:30 MDT 2019 by andrewstewart +\* Last modified Fri Aug 23 15:53:38 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 64879ff0db2d7ce70c514ee3dd418ffe95ebe8ee Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Fri, 23 Aug 2019 16:13:13 -0600 Subject: [PATCH 04/66] wip --- ForceMove/ForceMove.tla | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 15768a7..e813a39 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -45,14 +45,6 @@ challenge := [ end macro; -macro processChallenge() -begin skip; end macro; - -macro respondToChallenge() -begin -skip; -end macro; - fair process adjudicator = 0 begin (***************************************************************************) @@ -88,12 +80,14 @@ end process; fair process eve = 2 begin -(**************************************************************************** -Eve can do almost anything. She has k different histories that each -contain commitments 1...(n-1). She can sign any data with any private -key other than Alice's. She can call any adjudicator function, at any -time. She can front-run any transaction an arbitrary number of times -- ie. if anyone else calls an adjudicator function, she can then choose to call -****************************************************************************) +(***************************************************************************) +(* Eve can do almost anything. She has k different histories that each *) +(* contain commitments 1...(n-1). She can sign any data with any private *) +(* key other than Alice's. She can call any adjudicator function, at any *) +(* time. She can front-run any transaction an arbitrary number of times: *) +(* if anyone else calls an adjudicator function in a transaction tx, she *) +(* can then choose to submit any transaction before tx is mined. *) +(***************************************************************************) HandleChallenge: while challenge.status # ChallengeStatus.EXPIRED do @@ -109,10 +103,10 @@ end algorithm; \* BEGIN TRANSLATION -\* Label HandleChallenge of process adjudicator at line 62 col 1 changed to HandleChallenge_ -\* Label ExpireChallenge of process adjudicator at line 66 col 9 changed to ExpireChallenge_ -\* Label HandleChallenge of process alice at line 81 col 1 changed to HandleChallenge_a -\* Label ExpireChallenge of process alice at line 85 col 9 changed to ExpireChallenge_a +\* Label HandleChallenge of process adjudicator at line 54 col 1 changed to HandleChallenge_ +\* Label ExpireChallenge of process adjudicator at line 58 col 9 changed to ExpireChallenge_ +\* Label HandleChallenge of process alice at line 73 col 1 changed to HandleChallenge_a +\* Label ExpireChallenge of process alice at line 77 col 9 changed to ExpireChallenge_a VARIABLES challenge, submittedChallenge, pc (* define statement *) @@ -222,5 +216,5 @@ AllowedChallenges == ============================================================================= \* Modification History -\* Last modified Fri Aug 23 15:53:38 MDT 2019 by andrewstewart +\* Last modified Fri Aug 23 16:08:24 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 634542a77946c3d26da0d9e7957555f5308285aa Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Fri, 23 Aug 2019 16:16:48 -0600 Subject: [PATCH 05/66] wip --- ForceMove/ForceMove.tla | 103 +++++++++++++++------------------------- 1 file changed, 37 insertions(+), 66 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index e813a39..5b72731 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -59,23 +59,17 @@ do end while; end process; -fair process alice = 1 +fair process archie = 1 begin (***************************************************************************) -(* Alice has commitments (n - numParticipants)..(n-1). She wants to end *) -(* up with commitments (n - numParticipants + 1)..n. She is allowed to: *) -(* - Call forceMove with any states that she currently has *) -(* - Call refute with any state that she has *) +(* Alice has commitments (n - numParticipants)..(n-1). He wants to end *) +(* up with commitments (n - numParticipants + 1)..n. He is allowed to: *) +(* - Call forceMove with any states that he currently has *) +(* - Call refute with any state that he has *) (* - Call respondWithMove whenever there's an active challenge forcing *) -(* her to move *) +(* his to move *) (***************************************************************************) -HandleChallenge: -while challenge.status # ChallengeStatus.EXPIRED -do - await challenge.status = ChallengeStatus.ACTIVE; - ExpireChallenge: - challenge := [ status |-> ChallengeStatus.EXPIRED ] @@ challenge; -end while; +AliceMoves: skip; end process; fair process eve = 2 @@ -86,15 +80,10 @@ begin (* key other than Alice's. She can call any adjudicator function, at any *) (* time. She can front-run any transaction an arbitrary number of times: *) (* if anyone else calls an adjudicator function in a transaction tx, she *) -(* can then choose to submit any transaction before tx is mined. *) +(* can then choose to submit any transaction before tx is mined. She can *) +(* expire challenges whenever the current challenge doesn't allow *) (***************************************************************************) -HandleChallenge: -while challenge.status # ChallengeStatus.EXPIRED -do - await challenge.status = ChallengeStatus.ACTIVE; - ExpireChallenge: - challenge := [ status |-> ChallengeStatus.EXPIRED ] @@ challenge; -end while; +EveMoves: skip; end process; @@ -103,10 +92,6 @@ end algorithm; \* BEGIN TRANSLATION -\* Label HandleChallenge of process adjudicator at line 54 col 1 changed to HandleChallenge_ -\* Label ExpireChallenge of process adjudicator at line 58 col 9 changed to ExpireChallenge_ -\* Label HandleChallenge of process alice at line 73 col 1 changed to HandleChallenge_a -\* Label ExpireChallenge of process alice at line 77 col 9 changed to ExpireChallenge_a VARIABLES challenge, submittedChallenge, pc (* define statement *) @@ -121,62 +106,48 @@ ProcSet == {0} \cup {1} \cup {2} Init == (* Global variables *) /\ challenge = [turnNumber |-> 0, challengeStatus |-> ChallengeStatus.CLEARED] /\ submittedChallenge = NULL - /\ pc = [self \in ProcSet |-> CASE self = 0 -> "HandleChallenge_" - [] self = 1 -> "HandleChallenge_a" - [] self = 2 -> "HandleChallenge"] - -HandleChallenge_ == /\ pc[0] = "HandleChallenge_" - /\ IF challenge.status # ChallengeStatus.EXPIRED - THEN /\ challenge.status = ChallengeStatus.ACTIVE - /\ pc' = [pc EXCEPT ![0] = "ExpireChallenge_"] - ELSE /\ pc' = [pc EXCEPT ![0] = "Done"] - /\ UNCHANGED << challenge, submittedChallenge >> - -ExpireChallenge_ == /\ pc[0] = "ExpireChallenge_" - /\ challenge' = [ status |-> ChallengeStatus.EXPIRED ] @@ challenge - /\ pc' = [pc EXCEPT ![0] = "HandleChallenge_"] - /\ UNCHANGED submittedChallenge - -adjudicator == HandleChallenge_ \/ ExpireChallenge_ - -HandleChallenge_a == /\ pc[1] = "HandleChallenge_a" - /\ IF challenge.status # ChallengeStatus.EXPIRED - THEN /\ challenge.status = ChallengeStatus.ACTIVE - /\ pc' = [pc EXCEPT ![1] = "ExpireChallenge_a"] - ELSE /\ pc' = [pc EXCEPT ![1] = "Done"] - /\ UNCHANGED << challenge, submittedChallenge >> - -ExpireChallenge_a == /\ pc[1] = "ExpireChallenge_a" - /\ challenge' = [ status |-> ChallengeStatus.EXPIRED ] @@ challenge - /\ pc' = [pc EXCEPT ![1] = "HandleChallenge_a"] - /\ UNCHANGED submittedChallenge - -alice == HandleChallenge_a \/ ExpireChallenge_a - -HandleChallenge == /\ pc[2] = "HandleChallenge" + /\ pc = [self \in ProcSet |-> CASE self = 0 -> "HandleChallenge" + [] self = 1 -> "AliceMoves" + [] self = 2 -> "EveMoves"] + +HandleChallenge == /\ pc[0] = "HandleChallenge" /\ IF challenge.status # ChallengeStatus.EXPIRED THEN /\ challenge.status = ChallengeStatus.ACTIVE - /\ pc' = [pc EXCEPT ![2] = "ExpireChallenge"] - ELSE /\ pc' = [pc EXCEPT ![2] = "Done"] + /\ pc' = [pc EXCEPT ![0] = "ExpireChallenge"] + ELSE /\ pc' = [pc EXCEPT ![0] = "Done"] /\ UNCHANGED << challenge, submittedChallenge >> -ExpireChallenge == /\ pc[2] = "ExpireChallenge" +ExpireChallenge == /\ pc[0] = "ExpireChallenge" /\ challenge' = [ status |-> ChallengeStatus.EXPIRED ] @@ challenge - /\ pc' = [pc EXCEPT ![2] = "HandleChallenge"] + /\ pc' = [pc EXCEPT ![0] = "HandleChallenge"] /\ UNCHANGED submittedChallenge -eve == HandleChallenge \/ ExpireChallenge +adjudicator == HandleChallenge \/ ExpireChallenge + +AliceMoves == /\ pc[1] = "AliceMoves" + /\ TRUE + /\ pc' = [pc EXCEPT ![1] = "Done"] + /\ UNCHANGED << challenge, submittedChallenge >> + +archie == AliceMoves + +EveMoves == /\ pc[2] = "EveMoves" + /\ TRUE + /\ pc' = [pc EXCEPT ![2] = "Done"] + /\ UNCHANGED << challenge, submittedChallenge >> + +eve == EveMoves (* Allow infinite stuttering to prevent deadlock on termination. *) Terminating == /\ \A self \in ProcSet: pc[self] = "Done" /\ UNCHANGED vars -Next == adjudicator \/ alice \/ eve +Next == adjudicator \/ archie \/ eve \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(adjudicator) - /\ WF_vars(alice) + /\ WF_vars(archie) /\ WF_vars(eve) Termination == <>(\A self \in ProcSet: pc[self] = "Done") @@ -216,5 +187,5 @@ AllowedChallenges == ============================================================================= \* Modification History -\* Last modified Fri Aug 23 16:08:24 MDT 2019 by andrewstewart +\* Last modified Fri Aug 23 16:16:46 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From ef59a33ee89aeb3a106d66005cf5f2455b5cac11 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Fri, 23 Aug 2019 16:37:22 -0600 Subject: [PATCH 06/66] wip --- ForceMove/ForceMove.tla | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 5b72731..4679332 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -53,9 +53,15 @@ begin HandleChallenge: while challenge.status # ChallengeStatus.EXPIRED do - await challenge.status = ChallengeStatus.ACTIVE; - ExpireChallenge: - challenge := [ status |-> ChallengeStatus.EXPIRED ] @@ challenge; + either + ExpireChallenge: + await challenge.status = ChallengeStatus.ACTIVE; + challenge := [ status |-> ChallengeStatus.EXPIRED ] @@ challenge; + or + RecordChallenge: + await submittedChallenge # NULL; + challenge := submittedChallenge; + end either; end while; end process; @@ -63,18 +69,20 @@ fair process archie = 1 begin (***************************************************************************) (* Alice has commitments (n - numParticipants)..(n-1). He wants to end *) -(* up with commitments (n - numParticipants + 1)..n. He is allowed to: *) +(* up with commitments (n - numParticipants + 1)..n. *) +(* *) +(* He is allowed to: *) (* - Call forceMove with any states that he currently has *) (* - Call refute with any state that he has *) -(* - Call respondWithMove whenever there's an active challenge forcing *) -(* his to move *) +(* - Call respondWithMove or respondWithMove whenever there's an active *) +(* challenge where it's his turn to move *) (***************************************************************************) AliceMoves: skip; end process; fair process eve = 2 begin -(***************************************************************************) +(****************************************************************************) (* Eve can do almost anything. She has k different histories that each *) (* contain commitments 1...(n-1). She can sign any data with any private *) (* key other than Alice's. She can call any adjudicator function, at any *) @@ -112,17 +120,24 @@ Init == (* Global variables *) HandleChallenge == /\ pc[0] = "HandleChallenge" /\ IF challenge.status # ChallengeStatus.EXPIRED - THEN /\ challenge.status = ChallengeStatus.ACTIVE - /\ pc' = [pc EXCEPT ![0] = "ExpireChallenge"] + THEN /\ \/ /\ pc' = [pc EXCEPT ![0] = "ExpireChallenge"] + \/ /\ pc' = [pc EXCEPT ![0] = "RecordChallenge"] ELSE /\ pc' = [pc EXCEPT ![0] = "Done"] /\ UNCHANGED << challenge, submittedChallenge >> ExpireChallenge == /\ pc[0] = "ExpireChallenge" + /\ challenge.status = ChallengeStatus.ACTIVE /\ challenge' = [ status |-> ChallengeStatus.EXPIRED ] @@ challenge /\ pc' = [pc EXCEPT ![0] = "HandleChallenge"] /\ UNCHANGED submittedChallenge -adjudicator == HandleChallenge \/ ExpireChallenge +RecordChallenge == /\ pc[0] = "RecordChallenge" + /\ submittedChallenge # NULL + /\ challenge' = submittedChallenge + /\ pc' = [pc EXCEPT ![0] = "HandleChallenge"] + /\ UNCHANGED submittedChallenge + +adjudicator == HandleChallenge \/ ExpireChallenge \/ RecordChallenge AliceMoves == /\ pc[1] = "AliceMoves" /\ TRUE @@ -187,5 +202,5 @@ AllowedChallenges == ============================================================================= \* Modification History -\* Last modified Fri Aug 23 16:16:46 MDT 2019 by andrewstewart +\* Last modified Fri Aug 23 16:37:17 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From bf63d046e7ff3939d25cbfdb0ad5e67aeeca005a Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Fri, 23 Aug 2019 16:39:23 -0600 Subject: [PATCH 07/66] wip --- ForceMove/ForceMove.tla | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 4679332..f4025b9 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -35,12 +35,23 @@ mover(turnNumber) == 1 + ((turnNumber-1) % NumParticipants) challengeIsPresent == challenge.status # ChallengeStatus.CLEARED end define; -macro forceMove(turnNumber, votesRequired) +macro respondWithMove(turnNumber, signer) +begin skip; +end macro; + +macro respondWithAlternativeMove(turnNumber, signer) +begin skip; +end macro; + +macro refute(turnNumber, signer) +begin skip; +end macro; + +macro forceMove(turnNumber) begin -challenge := [ +submittedChallenge := [ turnNumber |-> turnNumber, - status |-> ChallengeStatus.ACTIVE, - votesRequired |-> votesRequired + status |-> ChallengeStatus.ACTIVE ]; end macro; @@ -202,5 +213,5 @@ AllowedChallenges == ============================================================================= \* Modification History -\* Last modified Fri Aug 23 16:37:17 MDT 2019 by andrewstewart +\* Last modified Fri Aug 23 16:38:52 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 3bf6583c6e7c41043363c3fd6d307e2efb00fa20 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Mon, 26 Aug 2019 10:23:40 -0600 Subject: [PATCH 08/66] wip --- ForceMove/ForceMove.tla | 61 +++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index f4025b9..90457ca 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -1,10 +1,10 @@ ----------------------------- MODULE ForceMove ----------------------------- EXTENDS Integers, Sequences, FiniteSets, TLC CONSTANTS - Alice, \* A model value + Archie, \* A model value Names, \* A set of model values Participants, \* A set of model values - NumHistories, + Histories, NULL \* A model value representing null. ChallengeStatus == [ @@ -16,12 +16,16 @@ ChallengeStatus == [ Range(f) == { f[x] : x \in DOMAIN f } StartingTurnNumber == 1 NumParticipants == Len(Participants) +AllowedHistories == {} +MainHistory == Histories[0] +ArchiesHistory == LET start == Len(Histories[0]) - NumParticipants + IN [i \in start..(start + NumParticipants - 1) |-> MainHistory[i]] ASSUME - /\ Alice \in Names + /\ Archie \in Names /\ Cardinality(Names) = NumParticipants /\ Len(Participants) >= 2 - /\ NumHistories \in Nat + /\ Histories \in AllowedHistories /\ \A p \in Range(Participants) : p \in Names (* --algorithm forceMove @@ -47,19 +51,23 @@ macro refute(turnNumber, signer) begin skip; end macro; -macro forceMove(turnNumber) +macro forceMove(turnNumber, signer) begin -submittedChallenge := [ - turnNumber |-> turnNumber, - status |-> ChallengeStatus.ACTIVE -]; +if TRUE then skip; \* TODO: Check conditions on the submitted challenge +else + submittedChallenge := [ + turnNumber |-> turnNumber, + status |-> ChallengeStatus.ACTIVE + ]; +end if; end macro; fair process adjudicator = 0 begin (***************************************************************************) -(* This process expires challenges. *) +(* This process expires active challenges and records submitted *) +(* challenges. *) (***************************************************************************) HandleChallenge: while challenge.status # ChallengeStatus.EXPIRED @@ -71,7 +79,11 @@ do or RecordChallenge: await submittedChallenge # NULL; - challenge := submittedChallenge; + if challenge.status # ChallengeStatus.CLEARED then skip; + else + challenge := submittedChallenge; + submittedChallenge := NULL; + end if; end either; end while; end process; @@ -79,7 +91,7 @@ end process; fair process archie = 1 begin (***************************************************************************) -(* Alice has commitments (n - numParticipants)..(n-1). He wants to end *) +(* Archie has commitments (n - numParticipants)..(n-1). He wants to end *) (* up with commitments (n - numParticipants + 1)..n. *) (* *) (* He is allowed to: *) @@ -88,7 +100,7 @@ begin (* - Call respondWithMove or respondWithMove whenever there's an active *) (* challenge where it's his turn to move *) (***************************************************************************) -AliceMoves: skip; +ArchieMoves: skip; end process; fair process eve = 2 @@ -96,7 +108,7 @@ begin (****************************************************************************) (* Eve can do almost anything. She has k different histories that each *) (* contain commitments 1...(n-1). She can sign any data with any private *) -(* key other than Alice's. She can call any adjudicator function, at any *) +(* key other than Archie's. She can call any adjudicator function, at any *) (* time. She can front-run any transaction an arbitrary number of times: *) (* if anyone else calls an adjudicator function in a transaction tx, she *) (* can then choose to submit any transaction before tx is mined. She can *) @@ -126,7 +138,7 @@ Init == (* Global variables *) /\ challenge = [turnNumber |-> 0, challengeStatus |-> ChallengeStatus.CLEARED] /\ submittedChallenge = NULL /\ pc = [self \in ProcSet |-> CASE self = 0 -> "HandleChallenge" - [] self = 1 -> "AliceMoves" + [] self = 1 -> "ArchieMoves" [] self = 2 -> "EveMoves"] HandleChallenge == /\ pc[0] = "HandleChallenge" @@ -144,18 +156,21 @@ ExpireChallenge == /\ pc[0] = "ExpireChallenge" RecordChallenge == /\ pc[0] = "RecordChallenge" /\ submittedChallenge # NULL - /\ challenge' = submittedChallenge + /\ IF challenge.status # ChallengeStatus.CLEARED + THEN /\ TRUE + /\ UNCHANGED << challenge, submittedChallenge >> + ELSE /\ challenge' = submittedChallenge + /\ submittedChallenge' = NULL /\ pc' = [pc EXCEPT ![0] = "HandleChallenge"] - /\ UNCHANGED submittedChallenge adjudicator == HandleChallenge \/ ExpireChallenge \/ RecordChallenge -AliceMoves == /\ pc[1] = "AliceMoves" - /\ TRUE - /\ pc' = [pc EXCEPT ![1] = "Done"] - /\ UNCHANGED << challenge, submittedChallenge >> +ArchieMoves == /\ pc[1] = "ArchieMoves" + /\ TRUE + /\ pc' = [pc EXCEPT ![1] = "Done"] + /\ UNCHANGED << challenge, submittedChallenge >> -archie == AliceMoves +archie == ArchieMoves EveMoves == /\ pc[2] = "EveMoves" /\ TRUE @@ -213,5 +228,5 @@ AllowedChallenges == ============================================================================= \* Modification History -\* Last modified Fri Aug 23 16:38:52 MDT 2019 by andrewstewart +\* Last modified Mon Aug 26 10:23:22 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 2fffcc2b0220c2e2ac7053936197bf74c268021d Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Mon, 26 Aug 2019 10:53:50 -0600 Subject: [PATCH 09/66] Use channel mode language from documentation --- ForceMove/ForceMove.tla | 79 +++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 90457ca..7fd83d9 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -7,18 +7,18 @@ CONSTANTS Histories, NULL \* A model value representing null. -ChallengeStatus == [ - CLEARED |-> "CLEARED", - ACTIVE |-> "ACTIVE", - EXPIRED |-> "EXPIRED" +ChannelMode == [ + OPEN |-> "OPEN", + CHALLENGE |-> "CHALLENGE", + FINALIZED |-> "FINALIZED" ] Range(f) == { f[x] : x \in DOMAIN f } StartingTurnNumber == 1 NumParticipants == Len(Participants) -AllowedHistories == {} +AllowedHistories == {} \* TODO: Fill out the allowed histories. MainHistory == Histories[0] -ArchiesHistory == LET start == Len(Histories[0]) - NumParticipants +ArchiesHistory == LET start == Len(MainHistory) - NumParticipants IN [i \in start..(start + NumParticipants - 1) |-> MainHistory[i]] ASSUME @@ -31,12 +31,12 @@ ASSUME (* --algorithm forceMove variables - challenge = [turnNumber |-> 0, challengeStatus |-> ChallengeStatus.CLEARED], + channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN], submittedChallenge = NULL define mover(turnNumber) == 1 + ((turnNumber-1) % NumParticipants) -challengeIsPresent == challenge.status # ChallengeStatus.CLEARED +challengeOngoing == channel.mode = ChannelMode.CHALLENGE end define; macro respondWithMove(turnNumber, signer) @@ -53,11 +53,11 @@ end macro; macro forceMove(turnNumber, signer) begin -if TRUE then skip; \* TODO: Check conditions on the submitted challenge +if TRUE then skip; \* TODO: Check conditions on the submitted channel else submittedChallenge := [ turnNumber |-> turnNumber, - status |-> ChallengeStatus.ACTIVE + mode |-> ChannelMode.CHALLENGE ]; end if; @@ -66,22 +66,24 @@ end macro; fair process adjudicator = 0 begin (***************************************************************************) -(* This process expires active challenges and records submitted *) -(* challenges. *) +(* This process expires active channels and records submitted *) +(* channels. *) (***************************************************************************) HandleChallenge: -while challenge.status # ChallengeStatus.EXPIRED +while channel.mode # ChannelMode.FINALIZED do either ExpireChallenge: - await challenge.status = ChallengeStatus.ACTIVE; - challenge := [ status |-> ChallengeStatus.EXPIRED ] @@ challenge; + await channel.mode = ChannelMode.CHALLENGE; + channel := [ mode |-> ChannelMode.FINALIZED ] @@ channel; or RecordChallenge: await submittedChallenge # NULL; - if challenge.status # ChallengeStatus.CLEARED then skip; - else - challenge := submittedChallenge; + if + /\ channel.mode # ChannelMode.OPEN + /\ channel.turnNumber < challenge.turnNumber + then + channel := [ turnNumber |-> challenge.turnNumber, mode |-> ChannelMode.CHALLENGE ]; submittedChallenge := NULL; end if; end either; @@ -98,7 +100,7 @@ begin (* - Call forceMove with any states that he currently has *) (* - Call refute with any state that he has *) (* - Call respondWithMove or respondWithMove whenever there's an active *) -(* challenge where it's his turn to move *) +(* channel where it's his turn to move *) (***************************************************************************) ArchieMoves: skip; end process; @@ -112,7 +114,7 @@ begin (* time. She can front-run any transaction an arbitrary number of times: *) (* if anyone else calls an adjudicator function in a transaction tx, she *) (* can then choose to submit any transaction before tx is mined. She can *) -(* expire challenges whenever the current challenge doesn't allow *) +(* expire channels whenever the current channel doesn't allow *) (***************************************************************************) EveMoves: skip; end process; @@ -123,44 +125,45 @@ end algorithm; \* BEGIN TRANSLATION -VARIABLES challenge, submittedChallenge, pc +VARIABLES channel, submittedChallenge, pc (* define statement *) mover(turnNumber) == 1 + ((turnNumber-1) % NumParticipants) -challengeIsPresent == challenge.status # ChallengeStatus.CLEARED +challengeOngoing == channel.mode = ChannelMode.CHALLENGE -vars == << challenge, submittedChallenge, pc >> +vars == << channel, submittedChallenge, pc >> ProcSet == {0} \cup {1} \cup {2} Init == (* Global variables *) - /\ challenge = [turnNumber |-> 0, challengeStatus |-> ChallengeStatus.CLEARED] + /\ channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN] /\ submittedChallenge = NULL /\ pc = [self \in ProcSet |-> CASE self = 0 -> "HandleChallenge" [] self = 1 -> "ArchieMoves" [] self = 2 -> "EveMoves"] HandleChallenge == /\ pc[0] = "HandleChallenge" - /\ IF challenge.status # ChallengeStatus.EXPIRED + /\ IF channel.mode # ChannelMode.FINALIZED THEN /\ \/ /\ pc' = [pc EXCEPT ![0] = "ExpireChallenge"] \/ /\ pc' = [pc EXCEPT ![0] = "RecordChallenge"] ELSE /\ pc' = [pc EXCEPT ![0] = "Done"] - /\ UNCHANGED << challenge, submittedChallenge >> + /\ UNCHANGED << channel, submittedChallenge >> ExpireChallenge == /\ pc[0] = "ExpireChallenge" - /\ challenge.status = ChallengeStatus.ACTIVE - /\ challenge' = [ status |-> ChallengeStatus.EXPIRED ] @@ challenge + /\ channel.mode = ChannelMode.CHALLENGE + /\ channel' = [ mode |-> ChannelMode.FINALIZED ] @@ channel /\ pc' = [pc EXCEPT ![0] = "HandleChallenge"] /\ UNCHANGED submittedChallenge RecordChallenge == /\ pc[0] = "RecordChallenge" /\ submittedChallenge # NULL - /\ IF challenge.status # ChallengeStatus.CLEARED - THEN /\ TRUE - /\ UNCHANGED << challenge, submittedChallenge >> - ELSE /\ challenge' = submittedChallenge + /\ IF /\ channel.mode # ChannelMode.OPEN + /\ channel.turnNumber < challenge.turnNumber + THEN /\ channel' = [ turnNumber |-> challenge.turnNumber, mode |-> ChannelMode.CHALLENGE ] /\ submittedChallenge' = NULL + ELSE /\ TRUE + /\ UNCHANGED << channel, submittedChallenge >> /\ pc' = [pc EXCEPT ![0] = "HandleChallenge"] adjudicator == HandleChallenge \/ ExpireChallenge \/ RecordChallenge @@ -168,14 +171,14 @@ adjudicator == HandleChallenge \/ ExpireChallenge \/ RecordChallenge ArchieMoves == /\ pc[1] = "ArchieMoves" /\ TRUE /\ pc' = [pc EXCEPT ![1] = "Done"] - /\ UNCHANGED << challenge, submittedChallenge >> + /\ UNCHANGED << channel, submittedChallenge >> archie == ArchieMoves EveMoves == /\ pc[2] = "EveMoves" /\ TRUE /\ pc' = [pc EXCEPT ![2] = "Done"] - /\ UNCHANGED << challenge, submittedChallenge >> + /\ UNCHANGED << channel, submittedChallenge >> eve == EveMoves @@ -199,14 +202,14 @@ AllowedTurnNumbers == 0..(StartingTurnNumber + NumParticipants) AllowedChallenges == [ turnNumber: AllowedTurnNumbers, - status: Range(ChallengeStatus) + mode: Range(ChannelMode) ] \* Safety properties \*TypeOK == -\* /\ challenge \in AllowedChallenges +\* /\ channel \in AllowedChallenges \* TODO: Get TurnNumberDoesNotDecrease and StaysTerminated \* For some reason, state[p].turnNumber' is not valid @@ -218,7 +221,7 @@ AllowedChallenges == \* Liveness properties \*ProtocolTerminatesWhenChallengeDoesNotExpire == -\* \/ <>[]( /\ challenge.status = ChallengeStatus.EXPIRED +\* \/ <>[]( /\ channel.mode = ChannelMode.FINALIZED \* /\ \E p \in ParticipantIndices: state[p].type = Types.TERMINATED) \* \/ (\A p \in ParticipantIndices: <>[](/\ state[p].type = Types.SUCCESS \* /\ state[p].turnNumber = StartingTurnNumber + NumParticipants)) @@ -228,5 +231,5 @@ AllowedChallenges == ============================================================================= \* Modification History -\* Last modified Mon Aug 26 10:23:22 MDT 2019 by andrewstewart +\* Last modified Mon Aug 26 10:53:26 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From c8f9ab7d4e7c107253c8e3f03e3071c9665e5cd0 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Mon, 26 Aug 2019 11:28:31 -0600 Subject: [PATCH 10/66] Write out checks and effects that contract functions have --- ForceMove/ForceMove.tla | 150 +++++++++++++++++++++++++++++----------- 1 file changed, 108 insertions(+), 42 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 7fd83d9..c41ad80 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -32,33 +32,67 @@ ASSUME variables channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN], - submittedChallenge = NULL + challenge = NULL define mover(turnNumber) == 1 + ((turnNumber-1) % NumParticipants) challengeOngoing == channel.mode = ChannelMode.CHALLENGE +channelOpen == channel.mode = ChannelMode.OPEN + +\* TODO: Fill out these checks. +roundIsValid(round) == TRUE +challengerSigIsValid(challenger) == TRUE +progressesChannel(round) == TRUE +validTransition(turnNumber, signer) == TRUE + end define; +macro clearChallenge(turnNumber) +begin +channel := [ turnNumber |-> turnNumber, mode |-> ChannelMode.OPEN ]; +end macro; + +macro setChallenge(turnNumber) +begin +channel := [ turnNumber |-> turnNumber, mode |-> ChannelMode.CHALLENGE ]; +end macro; + macro respondWithMove(turnNumber, signer) -begin skip; +begin +if + /\ challengeOngoing + /\ validTransition(signer, turnNumber) +then clearChallenge(turnNumber) +end if; end macro; -macro respondWithAlternativeMove(turnNumber, signer) -begin skip; +macro respondWithAlternativeMove(round, signer) +begin +if + /\ roundIsValid(round) + /\ challengeOngoing + /\ round[NumParticipants].turnNumber > channel.turnNumber +then clearChallenge(round[NumParticipants].turnNumber); +end if; end macro; -macro refute(turnNumber, signer) -begin skip; +macro refute(turnNumber) +begin +if + /\ challengeOngoing + /\ turnNumber > channel.turnNumber +then clearChallenge(channel.turnNumber); +end if; end macro; -macro forceMove(turnNumber, signer) +macro forceMove(turnNumber, round, challenger) begin -if TRUE then skip; \* TODO: Check conditions on the submitted channel -else - submittedChallenge := [ - turnNumber |-> turnNumber, - mode |-> ChannelMode.CHALLENGE - ]; +if + /\ roundIsValid(round) + /\ channelOpen + /\ challengerSigIsValid(challenger) + /\ progressesChannel(round) +then setChallenge(turnNumber) end if; end macro; @@ -78,14 +112,9 @@ do channel := [ mode |-> ChannelMode.FINALIZED ] @@ channel; or RecordChallenge: - await submittedChallenge # NULL; - if - /\ channel.mode # ChannelMode.OPEN - /\ channel.turnNumber < challenge.turnNumber - then - channel := [ turnNumber |-> challenge.turnNumber, mode |-> ChannelMode.CHALLENGE ]; - submittedChallenge := NULL; - end if; + await challenge # NULL; + channel := [ turnNumber |-> challenge.turnNumber, mode |-> ChannelMode.CHALLENGE ]; + challenge := NULL; end either; end while; end process; @@ -125,22 +154,29 @@ end algorithm; \* BEGIN TRANSLATION -VARIABLES channel, submittedChallenge, pc +VARIABLES channel, challenge, pc (* define statement *) mover(turnNumber) == 1 + ((turnNumber-1) % NumParticipants) challengeOngoing == channel.mode = ChannelMode.CHALLENGE +channelOpen == channel.mode = ChannelMode.OPEN + +roundIsValid(round) == TRUE +challengerSigIsValid(challenger) == TRUE +progressesChannel(round) == TRUE +validTransition(turnNumber, signer) == TRUE -vars == << channel, submittedChallenge, pc >> + +vars == << channel, challenge, pc >> ProcSet == {0} \cup {1} \cup {2} Init == (* Global variables *) /\ channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN] - /\ submittedChallenge = NULL + /\ challenge = NULL /\ pc = [self \in ProcSet |-> CASE self = 0 -> "HandleChallenge" - [] self = 1 -> "ArchieMoves" + [] self = 1 -> "One" [] self = 2 -> "EveMoves"] HandleChallenge == /\ pc[0] = "HandleChallenge" @@ -148,37 +184,67 @@ HandleChallenge == /\ pc[0] = "HandleChallenge" THEN /\ \/ /\ pc' = [pc EXCEPT ![0] = "ExpireChallenge"] \/ /\ pc' = [pc EXCEPT ![0] = "RecordChallenge"] ELSE /\ pc' = [pc EXCEPT ![0] = "Done"] - /\ UNCHANGED << channel, submittedChallenge >> + /\ UNCHANGED << channel, challenge >> ExpireChallenge == /\ pc[0] = "ExpireChallenge" /\ channel.mode = ChannelMode.CHALLENGE /\ channel' = [ mode |-> ChannelMode.FINALIZED ] @@ channel /\ pc' = [pc EXCEPT ![0] = "HandleChallenge"] - /\ UNCHANGED submittedChallenge + /\ UNCHANGED challenge RecordChallenge == /\ pc[0] = "RecordChallenge" - /\ submittedChallenge # NULL - /\ IF /\ channel.mode # ChannelMode.OPEN - /\ channel.turnNumber < challenge.turnNumber - THEN /\ channel' = [ turnNumber |-> challenge.turnNumber, mode |-> ChannelMode.CHALLENGE ] - /\ submittedChallenge' = NULL - ELSE /\ TRUE - /\ UNCHANGED << channel, submittedChallenge >> + /\ challenge # NULL + /\ channel' = [ turnNumber |-> challenge.turnNumber, mode |-> ChannelMode.CHALLENGE ] + /\ challenge' = NULL /\ pc' = [pc EXCEPT ![0] = "HandleChallenge"] adjudicator == HandleChallenge \/ ExpireChallenge \/ RecordChallenge -ArchieMoves == /\ pc[1] = "ArchieMoves" - /\ TRUE - /\ pc' = [pc EXCEPT ![1] = "Done"] - /\ UNCHANGED << channel, submittedChallenge >> - -archie == ArchieMoves +One == /\ pc[1] = "One" + /\ IF /\ roundIsValid(({})) + /\ channelOpen + /\ challengerSigIsValid(Archie) + /\ progressesChannel(({})) + THEN /\ channel' = [ turnNumber |-> 2, mode |-> ChannelMode.CHALLENGE ] + ELSE /\ TRUE + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![1] = "Two"] + /\ UNCHANGED challenge + +Two == /\ pc[1] = "Two" + /\ IF /\ challengeOngoing + /\ validTransition(Archie, 3) + THEN /\ channel' = [ turnNumber |-> 3, mode |-> ChannelMode.OPEN ] + ELSE /\ TRUE + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![1] = "Three"] + /\ UNCHANGED challenge + +Three == /\ pc[1] = "Three" + /\ IF /\ roundIsValid(({})) + /\ challengeOngoing + /\ ({})[NumParticipants].turnNumber > channel.turnNumber + THEN /\ channel' = [ turnNumber |-> (({})[NumParticipants].turnNumber), mode |-> ChannelMode.OPEN ] + ELSE /\ TRUE + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![1] = "Four"] + /\ UNCHANGED challenge + +Four == /\ pc[1] = "Four" + /\ IF /\ challengeOngoing + /\ 5 > channel.turnNumber + THEN /\ channel' = [ turnNumber |-> (channel.turnNumber), mode |-> ChannelMode.OPEN ] + ELSE /\ TRUE + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![1] = "Done"] + /\ UNCHANGED challenge + +archie == One \/ Two \/ Three \/ Four EveMoves == /\ pc[2] = "EveMoves" /\ TRUE /\ pc' = [pc EXCEPT ![2] = "Done"] - /\ UNCHANGED << channel, submittedChallenge >> + /\ UNCHANGED << channel, challenge >> eve == EveMoves @@ -231,5 +297,5 @@ AllowedChallenges == ============================================================================= \* Modification History -\* Last modified Mon Aug 26 10:53:26 MDT 2019 by andrewstewart +\* Last modified Mon Aug 26 11:29:08 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 48281432c5adc3d6a80ba404556f4667966f6245 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 27 Aug 2019 11:21:42 -0600 Subject: [PATCH 11/66] Start sketching out processes --- ForceMove/ForceMove.tla | 253 ++++++++++++++++++++++++---------------- 1 file changed, 152 insertions(+), 101 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index c41ad80..649eddd 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -5,6 +5,7 @@ CONSTANTS Names, \* A set of model values Participants, \* A set of model values Histories, + HistoryIDs, NULL \* A model value representing null. ChannelMode == [ @@ -16,17 +17,28 @@ ChannelMode == [ Range(f) == { f[x] : x \in DOMAIN f } StartingTurnNumber == 1 NumParticipants == Len(Participants) -AllowedHistories == {} \* TODO: Fill out the allowed histories. +AllowedHistories == [ start: Nat, length: Nat, id: HistoryIDs ] \* TODO: Fill out the allowed histories. MainHistory == Histories[0] -ArchiesHistory == LET start == Len(MainHistory) - NumParticipants - IN [i \in start..(start + NumParticipants - 1) |-> MainHistory[i]] + +Maximum(S) == + (*************************************************************************) + (* If $S$ is a set of numbers, then this define $Maximum(S)$ to be the *) + (* maximum of those numbers, or $-1$ if $S$ is empty. *) + (*************************************************************************) + LET Max[T \in SUBSET S] == + IF T = {} THEN -1 + ELSE LET n == CHOOSE n \in T : TRUE + rmax == Max[T \ {n}] + IN IF n \geq rmax THEN n ELSE rmax + IN Max[S] +ArchiesGoalTurnNumber == MainHistory.start + MainHistory.length ASSUME - /\ Archie \in Names - /\ Cardinality(Names) = NumParticipants + /\ Archie \notin Names + /\ NumParticipants = Cardinality(Names) + 1 /\ Len(Participants) >= 2 - /\ Histories \in AllowedHistories - /\ \A p \in Range(Participants) : p \in Names + /\ \A h \in Histories : h \in AllowedHistories + /\ Range(Participants) = { Archie } \cup Names (* --algorithm forceMove @@ -40,8 +52,7 @@ challengeOngoing == channel.mode = ChannelMode.CHALLENGE channelOpen == channel.mode = ChannelMode.OPEN \* TODO: Fill out these checks. -roundIsValid(round) == TRUE -challengerSigIsValid(challenger) == TRUE +challengerSigIsValid(challenger) == challenger \in Names progressesChannel(round) == TRUE validTransition(turnNumber, signer) == TRUE @@ -66,13 +77,13 @@ then clearChallenge(turnNumber) end if; end macro; -macro respondWithAlternativeMove(round, signer) +macro respondWithAlternativeMove(turnNumber, signer) +\* turnNumber is the turn number of the last state in the round. begin if - /\ roundIsValid(round) /\ challengeOngoing - /\ round[NumParticipants].turnNumber > channel.turnNumber -then clearChallenge(round[NumParticipants].turnNumber); + /\ turnNumber > channel.turnNumber +then clearChallenge(turnNumber); end if; end macro; @@ -109,6 +120,8 @@ do either ExpireChallenge: await channel.mode = ChannelMode.CHALLENGE; + \* TODO: How can we ensure that Archie can clear a challenge before it expires? + \* Maybe we should skip this step if it's his turn. channel := [ mode |-> ChannelMode.FINALIZED ] @@ channel; or RecordChallenge: @@ -119,41 +132,62 @@ do end while; end process; -fair process archie = 1 +fair process archie = Archie begin (***************************************************************************) -(* Archie has commitments (n - numParticipants)..(n-1). He wants to end *) +(* Archie has commitments (n - numParticipants)..(n-1). He wants to end *) (* up with commitments (n - numParticipants + 1)..n. *) (* *) (* He is allowed to: *) (* - Call forceMove with any states that he currently has *) (* - Call refute with any state that he has *) (* - Call respondWithMove or respondWithMove whenever there's an active *) -(* channel where it's his turn to move *) +(* challenge where it's his turn to move *) (***************************************************************************) -ArchieMoves: skip; +ArchieMoves: +either + await channel.mode = ChannelMode.CHALLENGE; + if TRUE then RespondWithMove: skip; + elsif TRUE then RespondWithAlternativeMove: skip; + elsif TRUE then Refute: skip; + end if; +or + await channel.mode = ChannelMode.OPEN; + ForceMove: skip; +end either; end process; -fair process eve = 2 +fair process eve \in HistoryIDs begin -(****************************************************************************) +(***************************************************************************) (* Eve can do almost anything. She has k different histories that each *) -(* contain commitments 1...(n-1). She can sign any data with any private *) -(* key other than Archie's. She can call any adjudicator function, at any *) -(* time. She can front-run any transaction an arbitrary number of times: *) -(* if anyone else calls an adjudicator function in a transaction tx, she *) -(* can then choose to submit any transaction before tx is mined. She can *) -(* expire channels whenever the current channel doesn't allow *) +(* contain commitments 1...(n-1), where one of them is the same history as *) +(* Archie's. She can sign any data with any private key other than *) +(* Archie's. She can call any adjudicator function, at any time. She can *) +(* front-run any transaction an arbitrary number of times: if anyone else *) +(* calls an adjudicator function in a transaction tx, she can then choose *) +(* to submit any transaction before tx is mined. She can choose not to do *) +(* anything, thus causing any active challenge to expire. *) (***************************************************************************) -EveMoves: skip; +EveMoves: +either + ForceMove: skip; +or RespondWithMove: skip; +or RespondWithAlternativeMove: skip; +or Refute: skip +or Sleep: skip; +end either; end process; - end algorithm; *) \* BEGIN TRANSLATION +\* Label ForceMove of process archie at line 148 col 28 changed to ForceMove_ +\* Label RespondWithMove of process archie at line 149 col 34 changed to RespondWithMove_ +\* Label RespondWithAlternativeMove of process archie at line 150 col 45 changed to RespondWithAlternativeMove_ +\* Label Refute of process archie at line 151 col 25 changed to Refute_ VARIABLES channel, challenge, pc (* define statement *) @@ -162,22 +196,21 @@ challengeOngoing == channel.mode = ChannelMode.CHALLENGE channelOpen == channel.mode = ChannelMode.OPEN -roundIsValid(round) == TRUE -challengerSigIsValid(challenger) == TRUE +challengerSigIsValid(challenger) == challenger \in Names progressesChannel(round) == TRUE validTransition(turnNumber, signer) == TRUE vars == << channel, challenge, pc >> -ProcSet == {0} \cup {1} \cup {2} +ProcSet == {0} \cup {Archie} \cup (HistoryIDs) Init == (* Global variables *) /\ channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN] /\ challenge = NULL /\ pc = [self \in ProcSet |-> CASE self = 0 -> "HandleChallenge" - [] self = 1 -> "One" - [] self = 2 -> "EveMoves"] + [] self = Archie -> "ArchieMoves" + [] self \in HistoryIDs -> "EveMoves"] HandleChallenge == /\ pc[0] = "HandleChallenge" /\ IF channel.mode # ChannelMode.FINALIZED @@ -200,72 +233,97 @@ RecordChallenge == /\ pc[0] = "RecordChallenge" adjudicator == HandleChallenge \/ ExpireChallenge \/ RecordChallenge -One == /\ pc[1] = "One" - /\ IF /\ roundIsValid(({})) - /\ channelOpen - /\ challengerSigIsValid(Archie) - /\ progressesChannel(({})) - THEN /\ channel' = [ turnNumber |-> 2, mode |-> ChannelMode.CHALLENGE ] - ELSE /\ TRUE - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![1] = "Two"] - /\ UNCHANGED challenge - -Two == /\ pc[1] = "Two" - /\ IF /\ challengeOngoing - /\ validTransition(Archie, 3) - THEN /\ channel' = [ turnNumber |-> 3, mode |-> ChannelMode.OPEN ] - ELSE /\ TRUE - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![1] = "Three"] - /\ UNCHANGED challenge - -Three == /\ pc[1] = "Three" - /\ IF /\ roundIsValid(({})) - /\ challengeOngoing - /\ ({})[NumParticipants].turnNumber > channel.turnNumber - THEN /\ channel' = [ turnNumber |-> (({})[NumParticipants].turnNumber), mode |-> ChannelMode.OPEN ] - ELSE /\ TRUE - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![1] = "Four"] - /\ UNCHANGED challenge - -Four == /\ pc[1] = "Four" - /\ IF /\ challengeOngoing - /\ 5 > channel.turnNumber - THEN /\ channel' = [ turnNumber |-> (channel.turnNumber), mode |-> ChannelMode.OPEN ] - ELSE /\ TRUE - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![1] = "Done"] - /\ UNCHANGED challenge - -archie == One \/ Two \/ Three \/ Four - -EveMoves == /\ pc[2] = "EveMoves" - /\ TRUE - /\ pc' = [pc EXCEPT ![2] = "Done"] - /\ UNCHANGED << channel, challenge >> - -eve == EveMoves +ArchieMoves == /\ pc[Archie] = "ArchieMoves" + /\ IF TRUE + THEN /\ pc' = [pc EXCEPT ![Archie] = "ForceMove_"] + ELSE /\ IF TRUE + THEN /\ pc' = [pc EXCEPT ![Archie] = "RespondWithMove_"] + ELSE /\ IF TRUE + THEN /\ pc' = [pc EXCEPT ![Archie] = "RespondWithAlternativeMove_"] + ELSE /\ IF TRUE + THEN /\ pc' = [pc EXCEPT ![Archie] = "Refute_"] + ELSE /\ pc' = [pc EXCEPT ![Archie] = "Done"] + /\ UNCHANGED << channel, challenge >> + +ForceMove_ == /\ pc[Archie] = "ForceMove_" + /\ TRUE + /\ pc' = [pc EXCEPT ![Archie] = "Done"] + /\ UNCHANGED << channel, challenge >> + +RespondWithMove_ == /\ pc[Archie] = "RespondWithMove_" + /\ TRUE + /\ pc' = [pc EXCEPT ![Archie] = "Done"] + /\ UNCHANGED << channel, challenge >> + +RespondWithAlternativeMove_ == /\ pc[Archie] = "RespondWithAlternativeMove_" + /\ TRUE + /\ pc' = [pc EXCEPT ![Archie] = "Done"] + /\ UNCHANGED << channel, challenge >> + +Refute_ == /\ pc[Archie] = "Refute_" + /\ TRUE + /\ pc' = [pc EXCEPT ![Archie] = "Done"] + /\ UNCHANGED << channel, challenge >> + +archie == ArchieMoves \/ ForceMove_ \/ RespondWithMove_ + \/ RespondWithAlternativeMove_ \/ Refute_ + +EveMoves(self) == /\ pc[self] = "EveMoves" + /\ \/ /\ pc' = [pc EXCEPT ![self] = "ForceMove"] + \/ /\ pc' = [pc EXCEPT ![self] = "RespondWithMove"] + \/ /\ pc' = [pc EXCEPT ![self] = "RespondWithAlternativeMove"] + \/ /\ pc' = [pc EXCEPT ![self] = "Refute"] + \/ /\ pc' = [pc EXCEPT ![self] = "Sleep"] + /\ UNCHANGED << channel, challenge >> + +ForceMove(self) == /\ pc[self] = "ForceMove" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ UNCHANGED << channel, challenge >> + +RespondWithMove(self) == /\ pc[self] = "RespondWithMove" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ UNCHANGED << channel, challenge >> + +RespondWithAlternativeMove(self) == /\ pc[self] = "RespondWithAlternativeMove" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ UNCHANGED << channel, challenge >> + +Refute(self) == /\ pc[self] = "Refute" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ UNCHANGED << channel, challenge >> + +Sleep(self) == /\ pc[self] = "Sleep" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ UNCHANGED << channel, challenge >> + +eve(self) == EveMoves(self) \/ ForceMove(self) \/ RespondWithMove(self) + \/ RespondWithAlternativeMove(self) \/ Refute(self) + \/ Sleep(self) (* Allow infinite stuttering to prevent deadlock on termination. *) Terminating == /\ \A self \in ProcSet: pc[self] = "Done" /\ UNCHANGED vars -Next == adjudicator \/ archie \/ eve +Next == adjudicator \/ archie + \/ (\E self \in HistoryIDs: eve(self)) \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(adjudicator) /\ WF_vars(archie) - /\ WF_vars(eve) + /\ \A self \in HistoryIDs : WF_vars(eve(self)) Termination == <>(\A self \in ProcSet: pc[self] = "Done") \* END TRANSLATION AllowedTurnNumbers == 0..(StartingTurnNumber + NumParticipants) -AllowedChallenges == +AllowedChannels == [ turnNumber: AllowedTurnNumbers, mode: Range(ChannelMode) @@ -274,28 +332,21 @@ AllowedChallenges == \* Safety properties -\*TypeOK == -\* /\ channel \in AllowedChallenges - -\* TODO: Get TurnNumberDoesNotDecrease and StaysTerminated -\* For some reason, state[p].turnNumber' is not valid -\*TurnNumberDoesNotDecrease == -\* /\ \A p \in ParticipantIndices: state[p].turnNumber' >= state[p].turnNumber - -\* Once a process has terminated, its state does not change. -\*StaysTerminated == \A p \in ParticipantIndices: (Terminated(state[p]) => (state'[p] = state[p])) +TypeOK == + /\ channel \in AllowedChannels \* Liveness properties -\*ProtocolTerminatesWhenChallengeDoesNotExpire == -\* \/ <>[]( /\ channel.mode = ChannelMode.FINALIZED -\* /\ \E p \in ParticipantIndices: state[p].type = Types.TERMINATED) -\* \/ (\A p \in ParticipantIndices: <>[](/\ state[p].type = Types.SUCCESS -\* /\ state[p].turnNumber = StartingTurnNumber + NumParticipants)) -\* \/ (\A p \in ParticipantIndices: <>[](/\ state[p].type = Types.ABORTED -\* /\ state[p].turnNumber = state[1].turnNumber)) - +ArchieCanProgressChannel == + \/ <>[]( + /\ channel.mode = ChannelMode.FINALIZED + /\ channel.turnNumber \in MainHistory.start..(MainHistory.start + MainHistory.length) + ) + \/ <>[]( + /\ channel.mode = ChannelMode.OPEN + /\ channel.turnNumber = ArchiesGoalTurnNumber + ) ============================================================================= \* Modification History -\* Last modified Mon Aug 26 11:29:08 MDT 2019 by andrewstewart +\* Last modified Tue Aug 27 11:20:48 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From c7dcd41d3aac5c34966a50613c5089c46ae3ddd5 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 27 Aug 2019 12:04:47 -0600 Subject: [PATCH 12/66] Refactor macros to use commitments --- ForceMove/ForceMove.tla | 94 ++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 649eddd..b821911 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -15,10 +15,10 @@ ChannelMode == [ ] Range(f) == { f[x] : x \in DOMAIN f } -StartingTurnNumber == 1 NumParticipants == Len(Participants) AllowedHistories == [ start: Nat, length: Nat, id: HistoryIDs ] \* TODO: Fill out the allowed histories. -MainHistory == Histories[0] +MainHistory == Histories[1] +StartingTurnNumber == MainHistory.start + MainHistory.length - 1 Maximum(S) == (*************************************************************************) @@ -37,13 +37,13 @@ ASSUME /\ Archie \notin Names /\ NumParticipants = Cardinality(Names) + 1 /\ Len(Participants) >= 2 - /\ \A h \in Histories : h \in AllowedHistories + /\ \A h \in Range(Histories) : h \in AllowedHistories /\ Range(Participants) = { Archie } \cup Names (* --algorithm forceMove variables - channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN], + channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN, history |-> MainHistory.id ], challenge = NULL define @@ -55,55 +55,58 @@ channelOpen == channel.mode = ChannelMode.OPEN challengerSigIsValid(challenger) == challenger \in Names progressesChannel(round) == TRUE validTransition(turnNumber, signer) == TRUE +validCommitment(c) == c \in [ turnNumber: Nat, history: HistoryIDs ] end define; -macro clearChallenge(turnNumber) +macro clearChallenge(commitment) begin -channel := [ turnNumber |-> turnNumber, mode |-> ChannelMode.OPEN ]; +assert validCommitment(commitment); +channel := [ mode |-> ChannelMode.OPEN ] @@ commitment; end macro; -macro setChallenge(turnNumber) +macro setChallenge(commitment) begin -channel := [ turnNumber |-> turnNumber, mode |-> ChannelMode.CHALLENGE ]; +assert validCommitment(commitment); +channel := [ mode |-> ChannelMode.CHALLENGE ] @@ commitment; end macro; -macro respondWithMove(turnNumber, signer) +macro respondWithMove(commitment, signer) begin if /\ challengeOngoing - /\ validTransition(signer, turnNumber) -then clearChallenge(turnNumber) + /\ validTransition(signer, commitment) +then clearChallenge(commitment); end if; end macro; -macro respondWithAlternativeMove(turnNumber, signer) +macro respondWithAlternativeMove(commitment, signer) \* turnNumber is the turn number of the last state in the round. begin if /\ challengeOngoing - /\ turnNumber > channel.turnNumber -then clearChallenge(turnNumber); + /\ commitment.turnNumber > channel.turnNumber +then clearChallenge(commitment); end if; end macro; -macro refute(turnNumber) +macro refute(commitment) begin if /\ challengeOngoing - /\ turnNumber > channel.turnNumber -then clearChallenge(channel.turnNumber); + /\ commitment.turnNumber > channel.turnNumber +then clearChallenge(commitment); end if; end macro; -macro forceMove(turnNumber, round, challenger) +macro forceMove(commitment, challenger) begin +assert validCommitment(commitment); if - /\ roundIsValid(round) /\ channelOpen /\ challengerSigIsValid(challenger) - /\ progressesChannel(round) -then setChallenge(turnNumber) + /\ progressesChannel(commitment.turnNumber) +then setChallenge(commitment) end if; end macro; @@ -184,10 +187,10 @@ end algorithm; \* BEGIN TRANSLATION -\* Label ForceMove of process archie at line 148 col 28 changed to ForceMove_ -\* Label RespondWithMove of process archie at line 149 col 34 changed to RespondWithMove_ -\* Label RespondWithAlternativeMove of process archie at line 150 col 45 changed to RespondWithAlternativeMove_ -\* Label Refute of process archie at line 151 col 25 changed to Refute_ +\* Label RespondWithMove of process archie at line 153 col 38 changed to RespondWithMove_ +\* Label RespondWithAlternativeMove of process archie at line 154 col 49 changed to RespondWithAlternativeMove_ +\* Label Refute of process archie at line 155 col 29 changed to Refute_ +\* Label ForceMove of process archie at line 159 col 16 changed to ForceMove_ VARIABLES channel, challenge, pc (* define statement *) @@ -199,6 +202,7 @@ channelOpen == channel.mode = ChannelMode.OPEN challengerSigIsValid(challenger) == challenger \in Names progressesChannel(round) == TRUE validTransition(turnNumber, signer) == TRUE +validCommitment(c) == c \in [ turnNumber: Nat, history: HistoryIDs ] vars == << channel, challenge, pc >> @@ -206,7 +210,7 @@ vars == << channel, challenge, pc >> ProcSet == {0} \cup {Archie} \cup (HistoryIDs) Init == (* Global variables *) - /\ channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN] + /\ channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN, history |-> MainHistory.id ] /\ challenge = NULL /\ pc = [self \in ProcSet |-> CASE self = 0 -> "HandleChallenge" [] self = Archie -> "ArchieMoves" @@ -234,22 +238,18 @@ RecordChallenge == /\ pc[0] = "RecordChallenge" adjudicator == HandleChallenge \/ ExpireChallenge \/ RecordChallenge ArchieMoves == /\ pc[Archie] = "ArchieMoves" - /\ IF TRUE - THEN /\ pc' = [pc EXCEPT ![Archie] = "ForceMove_"] - ELSE /\ IF TRUE - THEN /\ pc' = [pc EXCEPT ![Archie] = "RespondWithMove_"] - ELSE /\ IF TRUE - THEN /\ pc' = [pc EXCEPT ![Archie] = "RespondWithAlternativeMove_"] - ELSE /\ IF TRUE - THEN /\ pc' = [pc EXCEPT ![Archie] = "Refute_"] - ELSE /\ pc' = [pc EXCEPT ![Archie] = "Done"] + /\ \/ /\ channel.mode = ChannelMode.CHALLENGE + /\ IF TRUE + THEN /\ pc' = [pc EXCEPT ![Archie] = "RespondWithMove_"] + ELSE /\ IF TRUE + THEN /\ pc' = [pc EXCEPT ![Archie] = "RespondWithAlternativeMove_"] + ELSE /\ IF TRUE + THEN /\ pc' = [pc EXCEPT ![Archie] = "Refute_"] + ELSE /\ pc' = [pc EXCEPT ![Archie] = "Done"] + \/ /\ channel.mode = ChannelMode.OPEN + /\ pc' = [pc EXCEPT ![Archie] = "ForceMove_"] /\ UNCHANGED << channel, challenge >> -ForceMove_ == /\ pc[Archie] = "ForceMove_" - /\ TRUE - /\ pc' = [pc EXCEPT ![Archie] = "Done"] - /\ UNCHANGED << channel, challenge >> - RespondWithMove_ == /\ pc[Archie] = "RespondWithMove_" /\ TRUE /\ pc' = [pc EXCEPT ![Archie] = "Done"] @@ -265,8 +265,13 @@ Refute_ == /\ pc[Archie] = "Refute_" /\ pc' = [pc EXCEPT ![Archie] = "Done"] /\ UNCHANGED << channel, challenge >> -archie == ArchieMoves \/ ForceMove_ \/ RespondWithMove_ - \/ RespondWithAlternativeMove_ \/ Refute_ +ForceMove_ == /\ pc[Archie] = "ForceMove_" + /\ TRUE + /\ pc' = [pc EXCEPT ![Archie] = "Done"] + /\ UNCHANGED << channel, challenge >> + +archie == ArchieMoves \/ RespondWithMove_ \/ RespondWithAlternativeMove_ + \/ Refute_ \/ ForceMove_ EveMoves(self) == /\ pc[self] = "EveMoves" /\ \/ /\ pc' = [pc EXCEPT ![self] = "ForceMove"] @@ -326,7 +331,8 @@ AllowedTurnNumbers == 0..(StartingTurnNumber + NumParticipants) AllowedChannels == [ turnNumber: AllowedTurnNumbers, - mode: Range(ChannelMode) + mode: Range(ChannelMode), + history: HistoryIDs ] @@ -348,5 +354,5 @@ ArchieCanProgressChannel == ============================================================================= \* Modification History -\* Last modified Tue Aug 27 11:20:48 MDT 2019 by andrewstewart +\* Last modified Tue Aug 27 12:07:25 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 18bc1fcb650e3341f5be8a8cadfeac4a60176f8a Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 27 Aug 2019 12:49:44 -0600 Subject: [PATCH 13/66] Archie -> Alice --- ForceMove/ForceMove.tla | 94 ++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index b821911..500fb56 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -1,7 +1,7 @@ ----------------------------- MODULE ForceMove ----------------------------- EXTENDS Integers, Sequences, FiniteSets, TLC CONSTANTS - Archie, \* A model value + Alice, \* A model value Names, \* A set of model values Participants, \* A set of model values Histories, @@ -31,14 +31,14 @@ Maximum(S) == rmax == Max[T \ {n}] IN IF n \geq rmax THEN n ELSE rmax IN Max[S] -ArchiesGoalTurnNumber == MainHistory.start + MainHistory.length +AlicesGoalTurnNumber == MainHistory.start + MainHistory.length ASSUME - /\ Archie \notin Names + /\ Alice \notin Names /\ NumParticipants = Cardinality(Names) + 1 /\ Len(Participants) >= 2 /\ \A h \in Range(Histories) : h \in AllowedHistories - /\ Range(Participants) = { Archie } \cup Names + /\ Range(Participants) = { Alice } \cup Names (* --algorithm forceMove @@ -123,8 +123,8 @@ do either ExpireChallenge: await channel.mode = ChannelMode.CHALLENGE; - \* TODO: How can we ensure that Archie can clear a challenge before it expires? - \* Maybe we should skip this step if it's his turn. + \* TODO: How can we ensure that Alice can clear a challenge before it expires? + \* Maybe we should skip this step if it's her turn. channel := [ mode |-> ChannelMode.FINALIZED ] @@ channel; or RecordChallenge: @@ -135,19 +135,19 @@ do end while; end process; -fair process archie = Archie +fair process alice = Alice begin (***************************************************************************) -(* Archie has commitments (n - numParticipants)..(n-1). He wants to end *) +(* Alice has commitments (n - numParticipants)..(n-1). She wants to end *) (* up with commitments (n - numParticipants + 1)..n. *) (* *) -(* He is allowed to: *) -(* - Call forceMove with any states that he currently has *) -(* - Call refute with any state that he has *) +(* She is allowed to: *) +(* - Call forceMove with any states that she currently has *) +(* - Call refute with any state that she has *) (* - Call respondWithMove or respondWithMove whenever there's an active *) -(* challenge where it's his turn to move *) +(* challenge where it's her turn to move *) (***************************************************************************) -ArchieMoves: +AliceMoves: either await channel.mode = ChannelMode.CHALLENGE; if TRUE then RespondWithMove: skip; @@ -165,8 +165,8 @@ begin (***************************************************************************) (* Eve can do almost anything. She has k different histories that each *) (* contain commitments 1...(n-1), where one of them is the same history as *) -(* Archie's. She can sign any data with any private key other than *) -(* Archie's. She can call any adjudicator function, at any time. She can *) +(* Alice's. She can sign any data with any private key other than *) +(* Alice's. She can call any adjudicator function, at any time. She can *) (* front-run any transaction an arbitrary number of times: if anyone else *) (* calls an adjudicator function in a transaction tx, she can then choose *) (* to submit any transaction before tx is mined. She can choose not to do *) @@ -187,10 +187,10 @@ end algorithm; \* BEGIN TRANSLATION -\* Label RespondWithMove of process archie at line 153 col 38 changed to RespondWithMove_ -\* Label RespondWithAlternativeMove of process archie at line 154 col 49 changed to RespondWithAlternativeMove_ -\* Label Refute of process archie at line 155 col 29 changed to Refute_ -\* Label ForceMove of process archie at line 159 col 16 changed to ForceMove_ +\* Label RespondWithMove of process alice at line 153 col 38 changed to RespondWithMove_ +\* Label RespondWithAlternativeMove of process alice at line 154 col 49 changed to RespondWithAlternativeMove_ +\* Label Refute of process alice at line 155 col 29 changed to Refute_ +\* Label ForceMove of process alice at line 159 col 16 changed to ForceMove_ VARIABLES channel, challenge, pc (* define statement *) @@ -207,13 +207,13 @@ validCommitment(c) == c \in [ turnNumber: Nat, history: HistoryIDs ] vars == << channel, challenge, pc >> -ProcSet == {0} \cup {Archie} \cup (HistoryIDs) +ProcSet == {0} \cup {Alice} \cup (HistoryIDs) Init == (* Global variables *) /\ channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN, history |-> MainHistory.id ] /\ challenge = NULL /\ pc = [self \in ProcSet |-> CASE self = 0 -> "HandleChallenge" - [] self = Archie -> "ArchieMoves" + [] self = Alice -> "AliceMoves" [] self \in HistoryIDs -> "EveMoves"] HandleChallenge == /\ pc[0] = "HandleChallenge" @@ -237,40 +237,40 @@ RecordChallenge == /\ pc[0] = "RecordChallenge" adjudicator == HandleChallenge \/ ExpireChallenge \/ RecordChallenge -ArchieMoves == /\ pc[Archie] = "ArchieMoves" - /\ \/ /\ channel.mode = ChannelMode.CHALLENGE - /\ IF TRUE - THEN /\ pc' = [pc EXCEPT ![Archie] = "RespondWithMove_"] - ELSE /\ IF TRUE - THEN /\ pc' = [pc EXCEPT ![Archie] = "RespondWithAlternativeMove_"] - ELSE /\ IF TRUE - THEN /\ pc' = [pc EXCEPT ![Archie] = "Refute_"] - ELSE /\ pc' = [pc EXCEPT ![Archie] = "Done"] - \/ /\ channel.mode = ChannelMode.OPEN - /\ pc' = [pc EXCEPT ![Archie] = "ForceMove_"] - /\ UNCHANGED << channel, challenge >> +AliceMoves == /\ pc[Alice] = "AliceMoves" + /\ \/ /\ channel.mode = ChannelMode.CHALLENGE + /\ IF TRUE + THEN /\ pc' = [pc EXCEPT ![Alice] = "RespondWithMove_"] + ELSE /\ IF TRUE + THEN /\ pc' = [pc EXCEPT ![Alice] = "RespondWithAlternativeMove_"] + ELSE /\ IF TRUE + THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute_"] + ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] + \/ /\ channel.mode = ChannelMode.OPEN + /\ pc' = [pc EXCEPT ![Alice] = "ForceMove_"] + /\ UNCHANGED << channel, challenge >> -RespondWithMove_ == /\ pc[Archie] = "RespondWithMove_" +RespondWithMove_ == /\ pc[Alice] = "RespondWithMove_" /\ TRUE - /\ pc' = [pc EXCEPT ![Archie] = "Done"] + /\ pc' = [pc EXCEPT ![Alice] = "Done"] /\ UNCHANGED << channel, challenge >> -RespondWithAlternativeMove_ == /\ pc[Archie] = "RespondWithAlternativeMove_" +RespondWithAlternativeMove_ == /\ pc[Alice] = "RespondWithAlternativeMove_" /\ TRUE - /\ pc' = [pc EXCEPT ![Archie] = "Done"] + /\ pc' = [pc EXCEPT ![Alice] = "Done"] /\ UNCHANGED << channel, challenge >> -Refute_ == /\ pc[Archie] = "Refute_" +Refute_ == /\ pc[Alice] = "Refute_" /\ TRUE - /\ pc' = [pc EXCEPT ![Archie] = "Done"] + /\ pc' = [pc EXCEPT ![Alice] = "Done"] /\ UNCHANGED << channel, challenge >> -ForceMove_ == /\ pc[Archie] = "ForceMove_" +ForceMove_ == /\ pc[Alice] = "ForceMove_" /\ TRUE - /\ pc' = [pc EXCEPT ![Archie] = "Done"] + /\ pc' = [pc EXCEPT ![Alice] = "Done"] /\ UNCHANGED << channel, challenge >> -archie == ArchieMoves \/ RespondWithMove_ \/ RespondWithAlternativeMove_ +alice == AliceMoves \/ RespondWithMove_ \/ RespondWithAlternativeMove_ \/ Refute_ \/ ForceMove_ EveMoves(self) == /\ pc[self] = "EveMoves" @@ -314,13 +314,13 @@ eve(self) == EveMoves(self) \/ ForceMove(self) \/ RespondWithMove(self) Terminating == /\ \A self \in ProcSet: pc[self] = "Done" /\ UNCHANGED vars -Next == adjudicator \/ archie +Next == adjudicator \/ alice \/ (\E self \in HistoryIDs: eve(self)) \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(adjudicator) - /\ WF_vars(archie) + /\ WF_vars(alice) /\ \A self \in HistoryIDs : WF_vars(eve(self)) Termination == <>(\A self \in ProcSet: pc[self] = "Done") @@ -342,17 +342,17 @@ TypeOK == /\ channel \in AllowedChannels \* Liveness properties -ArchieCanProgressChannel == +AliceCanProgressChannel == \/ <>[]( /\ channel.mode = ChannelMode.FINALIZED /\ channel.turnNumber \in MainHistory.start..(MainHistory.start + MainHistory.length) ) \/ <>[]( /\ channel.mode = ChannelMode.OPEN - /\ channel.turnNumber = ArchiesGoalTurnNumber + /\ channel.turnNumber = AlicesGoalTurnNumber ) ============================================================================= \* Modification History -\* Last modified Tue Aug 27 12:07:25 MDT 2019 by andrewstewart +\* Last modified Tue Aug 27 12:52:53 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 5efcba14c822d0dcee1a76c091a6b06bd8ce929e Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 27 Aug 2019 13:25:16 -0600 Subject: [PATCH 14/66] Remove histories --- ForceMove/ForceMove.tla | 150 ++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 84 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 500fb56..b039eaf 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -2,10 +2,9 @@ EXTENDS Integers, Sequences, FiniteSets, TLC CONSTANTS Alice, \* A model value - Names, \* A set of model values - Participants, \* A set of model values - Histories, - HistoryIDs, + Eve, \* A set of model values + StartingTurnNumber, + NumParticipants, NULL \* A model value representing null. ChannelMode == [ @@ -15,35 +14,18 @@ ChannelMode == [ ] Range(f) == { f[x] : x \in DOMAIN f } -NumParticipants == Len(Participants) -AllowedHistories == [ start: Nat, length: Nat, id: HistoryIDs ] \* TODO: Fill out the allowed histories. -MainHistory == Histories[1] -StartingTurnNumber == MainHistory.start + MainHistory.length - 1 - -Maximum(S) == - (*************************************************************************) - (* If $S$ is a set of numbers, then this define $Maximum(S)$ to be the *) - (* maximum of those numbers, or $-1$ if $S$ is empty. *) - (*************************************************************************) - LET Max[T \in SUBSET S] == - IF T = {} THEN -1 - ELSE LET n == CHOOSE n \in T : TRUE - rmax == Max[T \ {n}] - IN IF n \geq rmax THEN n ELSE rmax - IN Max[S] -AlicesGoalTurnNumber == MainHistory.start + MainHistory.length + +AlicesGoalTurnNumber == StartingTurnNumber + NumParticipants +Names == { Alice, Eve } ASSUME - /\ Alice \notin Names - /\ NumParticipants = Cardinality(Names) + 1 - /\ Len(Participants) >= 2 - /\ \A h \in Range(Histories) : h \in AllowedHistories - /\ Range(Participants) = { Alice } \cup Names + /\ StartingTurnNumber \in Nat + /\ NumParticipants \in Nat \ { 1 } (* --algorithm forceMove variables - channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN, history |-> MainHistory.id ], + channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN ], challenge = NULL define @@ -55,7 +37,7 @@ channelOpen == channel.mode = ChannelMode.OPEN challengerSigIsValid(challenger) == challenger \in Names progressesChannel(round) == TRUE validTransition(turnNumber, signer) == TRUE -validCommitment(c) == c \in [ turnNumber: Nat, history: HistoryIDs ] +validCommitment(c) == c \in [ turnNumber: Nat ] end define; @@ -160,17 +142,20 @@ or end either; end process; -fair process eve \in HistoryIDs +fair process eve = Eve begin (***************************************************************************) -(* Eve can do almost anything. She has k different histories that each *) -(* contain commitments 1...(n-1), where one of them is the same history as *) -(* Alice's. She can sign any data with any private key other than *) -(* Alice's. She can call any adjudicator function, at any time. She can *) -(* front-run any transaction an arbitrary number of times: if anyone else *) -(* calls an adjudicator function in a transaction tx, she can then choose *) -(* to submit any transaction before tx is mined. She can choose not to do *) -(* anything, thus causing any active challenge to expire. *) +(* Eve can do almost anything. *) +(* *) +(* - She can sign any data with any private key, except she cannot sign *) +(* a commitment with Alice's private key when the turn number is in *) +(* StartingTurnNumber..(StartingTurnNumber + NumParticipants - 1) *) +(* - She can call any adjudicator function, at any time *) +(* - She can front-run any transaction an arbitrary number of times: if *) +(* anyone else calls an adjudicator function in a transaction tx, she *) +(* can then choose to submit any transaction before tx is mined. *) +(* - She can choose not to do anything, thus causing any active *) +(* challenge to expire. *) (***************************************************************************) EveMoves: either @@ -187,10 +172,10 @@ end algorithm; \* BEGIN TRANSLATION -\* Label RespondWithMove of process alice at line 153 col 38 changed to RespondWithMove_ -\* Label RespondWithAlternativeMove of process alice at line 154 col 49 changed to RespondWithAlternativeMove_ -\* Label Refute of process alice at line 155 col 29 changed to Refute_ -\* Label ForceMove of process alice at line 159 col 16 changed to ForceMove_ +\* Label RespondWithMove of process alice at line 135 col 38 changed to RespondWithMove_ +\* Label RespondWithAlternativeMove of process alice at line 136 col 49 changed to RespondWithAlternativeMove_ +\* Label Refute of process alice at line 137 col 29 changed to Refute_ +\* Label ForceMove of process alice at line 141 col 16 changed to ForceMove_ VARIABLES channel, challenge, pc (* define statement *) @@ -202,19 +187,19 @@ channelOpen == channel.mode = ChannelMode.OPEN challengerSigIsValid(challenger) == challenger \in Names progressesChannel(round) == TRUE validTransition(turnNumber, signer) == TRUE -validCommitment(c) == c \in [ turnNumber: Nat, history: HistoryIDs ] +validCommitment(c) == c \in [ turnNumber: Nat ] vars == << channel, challenge, pc >> -ProcSet == {0} \cup {Alice} \cup (HistoryIDs) +ProcSet == {0} \cup {Alice} \cup {Eve} Init == (* Global variables *) - /\ channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN, history |-> MainHistory.id ] + /\ channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN ] /\ challenge = NULL /\ pc = [self \in ProcSet |-> CASE self = 0 -> "HandleChallenge" [] self = Alice -> "AliceMoves" - [] self \in HistoryIDs -> "EveMoves"] + [] self = Eve -> "EveMoves"] HandleChallenge == /\ pc[0] = "HandleChallenge" /\ IF channel.mode # ChannelMode.FINALIZED @@ -271,57 +256,55 @@ ForceMove_ == /\ pc[Alice] = "ForceMove_" /\ UNCHANGED << channel, challenge >> alice == AliceMoves \/ RespondWithMove_ \/ RespondWithAlternativeMove_ - \/ Refute_ \/ ForceMove_ - -EveMoves(self) == /\ pc[self] = "EveMoves" - /\ \/ /\ pc' = [pc EXCEPT ![self] = "ForceMove"] - \/ /\ pc' = [pc EXCEPT ![self] = "RespondWithMove"] - \/ /\ pc' = [pc EXCEPT ![self] = "RespondWithAlternativeMove"] - \/ /\ pc' = [pc EXCEPT ![self] = "Refute"] - \/ /\ pc' = [pc EXCEPT ![self] = "Sleep"] - /\ UNCHANGED << channel, challenge >> - -ForceMove(self) == /\ pc[self] = "ForceMove" + \/ Refute_ \/ ForceMove_ + +EveMoves == /\ pc[Eve] = "EveMoves" + /\ \/ /\ pc' = [pc EXCEPT ![Eve] = "ForceMove"] + \/ /\ pc' = [pc EXCEPT ![Eve] = "RespondWithMove"] + \/ /\ pc' = [pc EXCEPT ![Eve] = "RespondWithAlternativeMove"] + \/ /\ pc' = [pc EXCEPT ![Eve] = "Refute"] + \/ /\ pc' = [pc EXCEPT ![Eve] = "Sleep"] + /\ UNCHANGED << channel, challenge >> + +ForceMove == /\ pc[Eve] = "ForceMove" + /\ TRUE + /\ pc' = [pc EXCEPT ![Eve] = "Done"] + /\ UNCHANGED << channel, challenge >> + +RespondWithMove == /\ pc[Eve] = "RespondWithMove" /\ TRUE - /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ pc' = [pc EXCEPT ![Eve] = "Done"] /\ UNCHANGED << channel, challenge >> -RespondWithMove(self) == /\ pc[self] = "RespondWithMove" - /\ TRUE - /\ pc' = [pc EXCEPT ![self] = "Done"] - /\ UNCHANGED << channel, challenge >> - -RespondWithAlternativeMove(self) == /\ pc[self] = "RespondWithAlternativeMove" - /\ TRUE - /\ pc' = [pc EXCEPT ![self] = "Done"] - /\ UNCHANGED << channel, challenge >> +RespondWithAlternativeMove == /\ pc[Eve] = "RespondWithAlternativeMove" + /\ TRUE + /\ pc' = [pc EXCEPT ![Eve] = "Done"] + /\ UNCHANGED << channel, challenge >> -Refute(self) == /\ pc[self] = "Refute" - /\ TRUE - /\ pc' = [pc EXCEPT ![self] = "Done"] - /\ UNCHANGED << channel, challenge >> +Refute == /\ pc[Eve] = "Refute" + /\ TRUE + /\ pc' = [pc EXCEPT ![Eve] = "Done"] + /\ UNCHANGED << channel, challenge >> -Sleep(self) == /\ pc[self] = "Sleep" - /\ TRUE - /\ pc' = [pc EXCEPT ![self] = "Done"] - /\ UNCHANGED << channel, challenge >> +Sleep == /\ pc[Eve] = "Sleep" + /\ TRUE + /\ pc' = [pc EXCEPT ![Eve] = "Done"] + /\ UNCHANGED << channel, challenge >> -eve(self) == EveMoves(self) \/ ForceMove(self) \/ RespondWithMove(self) - \/ RespondWithAlternativeMove(self) \/ Refute(self) - \/ Sleep(self) +eve == EveMoves \/ ForceMove \/ RespondWithMove + \/ RespondWithAlternativeMove \/ Refute \/ Sleep (* Allow infinite stuttering to prevent deadlock on termination. *) Terminating == /\ \A self \in ProcSet: pc[self] = "Done" /\ UNCHANGED vars -Next == adjudicator \/ alice - \/ (\E self \in HistoryIDs: eve(self)) +Next == adjudicator \/ alice \/ eve \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(adjudicator) /\ WF_vars(alice) - /\ \A self \in HistoryIDs : WF_vars(eve(self)) + /\ WF_vars(eve) Termination == <>(\A self \in ProcSet: pc[self] = "Done") @@ -331,8 +314,7 @@ AllowedTurnNumbers == 0..(StartingTurnNumber + NumParticipants) AllowedChannels == [ turnNumber: AllowedTurnNumbers, - mode: Range(ChannelMode), - history: HistoryIDs + mode: Range(ChannelMode) ] @@ -345,7 +327,7 @@ TypeOK == AliceCanProgressChannel == \/ <>[]( /\ channel.mode = ChannelMode.FINALIZED - /\ channel.turnNumber \in MainHistory.start..(MainHistory.start + MainHistory.length) + /\ channel.turnNumber \in StartingTurnNumber..AlicesGoalTurnNumber ) \/ <>[]( /\ channel.mode = ChannelMode.OPEN @@ -354,5 +336,5 @@ AliceCanProgressChannel == ============================================================================= \* Modification History -\* Last modified Tue Aug 27 12:52:53 MDT 2019 by andrewstewart +\* Last modified Tue Aug 27 13:28:29 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From d76fde919fddef4f55b12b9fc65f175a3873d7b9 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 27 Aug 2019 14:34:07 -0600 Subject: [PATCH 15/66] Update comment --- ForceMove/ForceMove.tla | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index b039eaf..3f45699 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -96,8 +96,8 @@ end macro; fair process adjudicator = 0 begin (***************************************************************************) -(* This process expires active channels and records submitted *) -(* channels. *) +(* This process expires active channels and records submitted *) +(* channels. *) (***************************************************************************) HandleChallenge: while channel.mode # ChannelMode.FINALIZED @@ -123,9 +123,9 @@ begin (* Alice has commitments (n - numParticipants)..(n-1). She wants to end *) (* up with commitments (n - numParticipants + 1)..n. *) (* *) -(* She is allowed to: *) -(* - Call forceMove with any states that she currently has *) -(* - Call refute with any state that she has *) +(* She is allowed to: *) +(* - Call forceMove with any states that she currently has *) +(* - Call refute with any state that she has *) (* - Call respondWithMove or respondWithMove whenever there's an active *) (* challenge where it's her turn to move *) (***************************************************************************) @@ -148,8 +148,8 @@ begin (* Eve can do almost anything. *) (* *) (* - She can sign any data with any private key, except she cannot sign *) -(* a commitment with Alice's private key when the turn number is in *) -(* StartingTurnNumber..(StartingTurnNumber + NumParticipants - 1) *) +(* a commitment with Alice's private key when the turn number is *) +(* greater than or equal to StartingTurnNumber *) (* - She can call any adjudicator function, at any time *) (* - She can front-run any transaction an arbitrary number of times: if *) (* anyone else calls an adjudicator function in a transaction tx, she *) @@ -336,5 +336,5 @@ AliceCanProgressChannel == ============================================================================= \* Modification History -\* Last modified Tue Aug 27 13:28:29 MDT 2019 by andrewstewart +\* Last modified Tue Aug 27 14:02:49 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 7da91751b6ac43cf3fdcb28cbe16350c1c0a2d70 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 27 Aug 2019 14:40:10 -0600 Subject: [PATCH 16/66] Processes loop --- ForceMove/ForceMove.tla | 116 ++++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 3f45699..aa19d1a 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -93,7 +93,7 @@ end if; end macro; -fair process adjudicator = 0 +fair process adjudicator = "Adjudicator" begin (***************************************************************************) (* This process expires active channels and records submitted *) @@ -130,16 +130,19 @@ begin (* challenge where it's her turn to move *) (***************************************************************************) AliceMoves: -either - await channel.mode = ChannelMode.CHALLENGE; - if TRUE then RespondWithMove: skip; - elsif TRUE then RespondWithAlternativeMove: skip; - elsif TRUE then Refute: skip; - end if; -or - await channel.mode = ChannelMode.OPEN; - ForceMove: skip; -end either; +while channel.turnNumber < AlicesGoalTurnNumber do + either + await channel.mode = ChannelMode.CHALLENGE; + if TRUE then RespondWithMove: skip; + elsif TRUE then RespondWithAlternativeMove: skip; + elsif TRUE then Refute: skip; + end if; + or + await channel.mode = ChannelMode.OPEN; + ForceMove: skip; + end either; + +end while; end process; fair process eve = Eve @@ -158,13 +161,15 @@ begin (* challenge to expire. *) (***************************************************************************) EveMoves: -either - ForceMove: skip; -or RespondWithMove: skip; -or RespondWithAlternativeMove: skip; -or Refute: skip -or Sleep: skip; -end either; +while TRUE do + either + ForceMove: skip; + or RespondWithMove: skip; + or RespondWithAlternativeMove: skip; + or Refute: skip + or Sleep: skip; + end either; +end while; end process; end algorithm; @@ -172,10 +177,10 @@ end algorithm; \* BEGIN TRANSLATION -\* Label RespondWithMove of process alice at line 135 col 38 changed to RespondWithMove_ -\* Label RespondWithAlternativeMove of process alice at line 136 col 49 changed to RespondWithAlternativeMove_ -\* Label Refute of process alice at line 137 col 29 changed to Refute_ -\* Label ForceMove of process alice at line 141 col 16 changed to ForceMove_ +\* Label RespondWithMove of process alice at line 136 col 42 changed to RespondWithMove_ +\* Label RespondWithAlternativeMove of process alice at line 137 col 53 changed to RespondWithAlternativeMove_ +\* Label Refute of process alice at line 138 col 33 changed to Refute_ +\* Label ForceMove of process alice at line 142 col 20 changed to ForceMove_ VARIABLES channel, challenge, pc (* define statement *) @@ -192,67 +197,69 @@ validCommitment(c) == c \in [ turnNumber: Nat ] vars == << channel, challenge, pc >> -ProcSet == {0} \cup {Alice} \cup {Eve} +ProcSet == {"Adjudicator"} \cup {Alice} \cup {Eve} Init == (* Global variables *) /\ channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN ] /\ challenge = NULL - /\ pc = [self \in ProcSet |-> CASE self = 0 -> "HandleChallenge" + /\ pc = [self \in ProcSet |-> CASE self = "Adjudicator" -> "HandleChallenge" [] self = Alice -> "AliceMoves" [] self = Eve -> "EveMoves"] -HandleChallenge == /\ pc[0] = "HandleChallenge" +HandleChallenge == /\ pc["Adjudicator"] = "HandleChallenge" /\ IF channel.mode # ChannelMode.FINALIZED - THEN /\ \/ /\ pc' = [pc EXCEPT ![0] = "ExpireChallenge"] - \/ /\ pc' = [pc EXCEPT ![0] = "RecordChallenge"] - ELSE /\ pc' = [pc EXCEPT ![0] = "Done"] + THEN /\ \/ /\ pc' = [pc EXCEPT !["Adjudicator"] = "ExpireChallenge"] + \/ /\ pc' = [pc EXCEPT !["Adjudicator"] = "RecordChallenge"] + ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "Done"] /\ UNCHANGED << channel, challenge >> -ExpireChallenge == /\ pc[0] = "ExpireChallenge" +ExpireChallenge == /\ pc["Adjudicator"] = "ExpireChallenge" /\ channel.mode = ChannelMode.CHALLENGE /\ channel' = [ mode |-> ChannelMode.FINALIZED ] @@ channel - /\ pc' = [pc EXCEPT ![0] = "HandleChallenge"] + /\ pc' = [pc EXCEPT !["Adjudicator"] = "HandleChallenge"] /\ UNCHANGED challenge -RecordChallenge == /\ pc[0] = "RecordChallenge" +RecordChallenge == /\ pc["Adjudicator"] = "RecordChallenge" /\ challenge # NULL /\ channel' = [ turnNumber |-> challenge.turnNumber, mode |-> ChannelMode.CHALLENGE ] /\ challenge' = NULL - /\ pc' = [pc EXCEPT ![0] = "HandleChallenge"] + /\ pc' = [pc EXCEPT !["Adjudicator"] = "HandleChallenge"] adjudicator == HandleChallenge \/ ExpireChallenge \/ RecordChallenge AliceMoves == /\ pc[Alice] = "AliceMoves" - /\ \/ /\ channel.mode = ChannelMode.CHALLENGE - /\ IF TRUE - THEN /\ pc' = [pc EXCEPT ![Alice] = "RespondWithMove_"] - ELSE /\ IF TRUE - THEN /\ pc' = [pc EXCEPT ![Alice] = "RespondWithAlternativeMove_"] + /\ IF channel.turnNumber < AlicesGoalTurnNumber + THEN /\ \/ /\ channel.mode = ChannelMode.CHALLENGE + /\ IF TRUE + THEN /\ pc' = [pc EXCEPT ![Alice] = "RespondWithMove_"] ELSE /\ IF TRUE - THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute_"] - ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] - \/ /\ channel.mode = ChannelMode.OPEN - /\ pc' = [pc EXCEPT ![Alice] = "ForceMove_"] + THEN /\ pc' = [pc EXCEPT ![Alice] = "RespondWithAlternativeMove_"] + ELSE /\ IF TRUE + THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute_"] + ELSE /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + \/ /\ channel.mode = ChannelMode.OPEN + /\ pc' = [pc EXCEPT ![Alice] = "ForceMove_"] + ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] /\ UNCHANGED << channel, challenge >> RespondWithMove_ == /\ pc[Alice] = "RespondWithMove_" /\ TRUE - /\ pc' = [pc EXCEPT ![Alice] = "Done"] + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED << channel, challenge >> RespondWithAlternativeMove_ == /\ pc[Alice] = "RespondWithAlternativeMove_" /\ TRUE - /\ pc' = [pc EXCEPT ![Alice] = "Done"] + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED << channel, challenge >> Refute_ == /\ pc[Alice] = "Refute_" /\ TRUE - /\ pc' = [pc EXCEPT ![Alice] = "Done"] + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED << channel, challenge >> ForceMove_ == /\ pc[Alice] = "ForceMove_" /\ TRUE - /\ pc' = [pc EXCEPT ![Alice] = "Done"] + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED << channel, challenge >> alice == AliceMoves \/ RespondWithMove_ \/ RespondWithAlternativeMove_ @@ -268,46 +275,39 @@ EveMoves == /\ pc[Eve] = "EveMoves" ForceMove == /\ pc[Eve] = "ForceMove" /\ TRUE - /\ pc' = [pc EXCEPT ![Eve] = "Done"] + /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] /\ UNCHANGED << channel, challenge >> RespondWithMove == /\ pc[Eve] = "RespondWithMove" /\ TRUE - /\ pc' = [pc EXCEPT ![Eve] = "Done"] + /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] /\ UNCHANGED << channel, challenge >> RespondWithAlternativeMove == /\ pc[Eve] = "RespondWithAlternativeMove" /\ TRUE - /\ pc' = [pc EXCEPT ![Eve] = "Done"] + /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] /\ UNCHANGED << channel, challenge >> Refute == /\ pc[Eve] = "Refute" /\ TRUE - /\ pc' = [pc EXCEPT ![Eve] = "Done"] + /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] /\ UNCHANGED << channel, challenge >> Sleep == /\ pc[Eve] = "Sleep" /\ TRUE - /\ pc' = [pc EXCEPT ![Eve] = "Done"] + /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] /\ UNCHANGED << channel, challenge >> eve == EveMoves \/ ForceMove \/ RespondWithMove \/ RespondWithAlternativeMove \/ Refute \/ Sleep -(* Allow infinite stuttering to prevent deadlock on termination. *) -Terminating == /\ \A self \in ProcSet: pc[self] = "Done" - /\ UNCHANGED vars - Next == adjudicator \/ alice \/ eve - \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(adjudicator) /\ WF_vars(alice) /\ WF_vars(eve) -Termination == <>(\A self \in ProcSet: pc[self] = "Done") - \* END TRANSLATION AllowedTurnNumbers == 0..(StartingTurnNumber + NumParticipants) @@ -336,5 +336,5 @@ AliceCanProgressChannel == ============================================================================= \* Modification History -\* Last modified Tue Aug 27 14:02:49 MDT 2019 by andrewstewart +\* Last modified Tue Aug 27 14:38:51 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 270f6fd99f61f979dc4be6518d311f45fc58d477 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 27 Aug 2019 15:18:57 -0600 Subject: [PATCH 17/66] Fix a few things --- ForceMove/ForceMove.tla | 103 ++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index aa19d1a..618af62 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -1,8 +1,8 @@ ----------------------------- MODULE ForceMove ----------------------------- EXTENDS Integers, Sequences, FiniteSets, TLC CONSTANTS - Alice, \* A model value - Eve, \* A set of model values + Alice, + Eve, StartingTurnNumber, NumParticipants, NULL \* A model value representing null. @@ -15,7 +15,8 @@ ChannelMode == [ Range(f) == { f[x] : x \in DOMAIN f } -AlicesGoalTurnNumber == StartingTurnNumber + NumParticipants +LatestTurnNumber == StartingTurnNumber + NumParticipants - 1 +AlicesGoalTurnNumber == LatestTurnNumber + 1 Names == { Alice, Eve } ASSUME @@ -50,7 +51,7 @@ end macro; macro setChallenge(commitment) begin assert validCommitment(commitment); -channel := [ mode |-> ChannelMode.CHALLENGE ] @@ commitment; +challenge := commitment; end macro; macro respondWithMove(commitment, signer) @@ -101,19 +102,20 @@ begin (***************************************************************************) HandleChallenge: while channel.mode # ChannelMode.FINALIZED -do - either - ExpireChallenge: - await channel.mode = ChannelMode.CHALLENGE; - \* TODO: How can we ensure that Alice can clear a challenge before it expires? - \* Maybe we should skip this step if it's her turn. - channel := [ mode |-> ChannelMode.FINALIZED ] @@ channel; - or +do + await \/ channel.mode = ChannelMode.CHALLENGE + \/ challenge # NULL; + if challenge = NULL + then + FinalizeChannel: + assert channel.mode = ChannelMode.CHALLENGE; + channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.turnNumber ]; + else RecordChallenge: - await challenge # NULL; - channel := [ turnNumber |-> challenge.turnNumber, mode |-> ChannelMode.CHALLENGE ]; - challenge := NULL; - end either; + assert challenge # NULL; + channel := [ turnNumber |-> challenge.turnNumber, mode |-> ChannelMode.CHALLENGE ]; + challenge := NULL; + end if; end while; end process; @@ -139,13 +141,13 @@ while channel.turnNumber < AlicesGoalTurnNumber do end if; or await channel.mode = ChannelMode.OPEN; - ForceMove: skip; + ForceMove: forceMove([ turnNumber |-> LatestTurnNumber ], Alice); end either; end while; end process; -fair process eve = Eve +process eve = Eve begin (***************************************************************************) (* Eve can do almost anything. *) @@ -177,10 +179,10 @@ end algorithm; \* BEGIN TRANSLATION -\* Label RespondWithMove of process alice at line 136 col 42 changed to RespondWithMove_ -\* Label RespondWithAlternativeMove of process alice at line 137 col 53 changed to RespondWithAlternativeMove_ -\* Label Refute of process alice at line 138 col 33 changed to Refute_ -\* Label ForceMove of process alice at line 142 col 20 changed to ForceMove_ +\* Label RespondWithMove of process alice at line 139 col 42 changed to RespondWithMove_ +\* Label RespondWithAlternativeMove of process alice at line 140 col 53 changed to RespondWithAlternativeMove_ +\* Label Refute of process alice at line 141 col 33 changed to Refute_ +\* Label ForceMove of process alice at line 88 col 1 changed to ForceMove_ VARIABLES channel, challenge, pc (* define statement *) @@ -208,24 +210,29 @@ Init == (* Global variables *) HandleChallenge == /\ pc["Adjudicator"] = "HandleChallenge" /\ IF channel.mode # ChannelMode.FINALIZED - THEN /\ \/ /\ pc' = [pc EXCEPT !["Adjudicator"] = "ExpireChallenge"] - \/ /\ pc' = [pc EXCEPT !["Adjudicator"] = "RecordChallenge"] + THEN /\ \/ channel.mode = ChannelMode.CHALLENGE + \/ challenge # NULL + /\ IF challenge = NULL + THEN /\ pc' = [pc EXCEPT !["Adjudicator"] = "FinalizeChannel"] + ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "RecordChallenge"] ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "Done"] /\ UNCHANGED << channel, challenge >> -ExpireChallenge == /\ pc["Adjudicator"] = "ExpireChallenge" - /\ channel.mode = ChannelMode.CHALLENGE - /\ channel' = [ mode |-> ChannelMode.FINALIZED ] @@ channel +FinalizeChannel == /\ pc["Adjudicator"] = "FinalizeChannel" + /\ Assert(channel.mode = ChannelMode.CHALLENGE, + "Failure of assertion at line 112, column 9.") + /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.turnNumber ] /\ pc' = [pc EXCEPT !["Adjudicator"] = "HandleChallenge"] /\ UNCHANGED challenge RecordChallenge == /\ pc["Adjudicator"] = "RecordChallenge" - /\ challenge # NULL + /\ Assert(challenge # NULL, + "Failure of assertion at line 116, column 9.") /\ channel' = [ turnNumber |-> challenge.turnNumber, mode |-> ChannelMode.CHALLENGE ] /\ challenge' = NULL /\ pc' = [pc EXCEPT !["Adjudicator"] = "HandleChallenge"] -adjudicator == HandleChallenge \/ ExpireChallenge \/ RecordChallenge +adjudicator == HandleChallenge \/ FinalizeChannel \/ RecordChallenge AliceMoves == /\ pc[Alice] = "AliceMoves" /\ IF channel.turnNumber < AlicesGoalTurnNumber @@ -258,9 +265,18 @@ Refute_ == /\ pc[Alice] = "Refute_" /\ UNCHANGED << channel, challenge >> ForceMove_ == /\ pc[Alice] = "ForceMove_" - /\ TRUE + /\ Assert(validCommitment(([ turnNumber |-> LatestTurnNumber ])), + "Failure of assertion at line 88, column 1 of macro called at line 145, column 20.") + /\ IF /\ channelOpen + /\ challengerSigIsValid(Alice) + /\ progressesChannel(([ turnNumber |-> LatestTurnNumber ]).turnNumber) + THEN /\ Assert(validCommitment(([ turnNumber |-> LatestTurnNumber ])), + "Failure of assertion at line 54, column 1 of macro called at line 145, column 20.") + /\ challenge' = [ turnNumber |-> LatestTurnNumber ] + ELSE /\ TRUE + /\ UNCHANGED challenge /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED << channel, challenge >> + /\ UNCHANGED channel alice == AliceMoves \/ RespondWithMove_ \/ RespondWithAlternativeMove_ \/ Refute_ \/ ForceMove_ @@ -306,7 +322,6 @@ Next == adjudicator \/ alice \/ eve Spec == /\ Init /\ [][Next]_vars /\ WF_vars(adjudicator) /\ WF_vars(alice) - /\ WF_vars(eve) \* END TRANSLATION @@ -324,17 +339,21 @@ TypeOK == /\ channel \in AllowedChannels \* Liveness properties -AliceCanProgressChannel == - \/ <>[]( - /\ channel.mode = ChannelMode.FINALIZED - /\ channel.turnNumber \in StartingTurnNumber..AlicesGoalTurnNumber - ) - \/ <>[]( - /\ channel.mode = ChannelMode.OPEN - /\ channel.turnNumber = AlicesGoalTurnNumber - ) +AliceCanProgressChannel == <>[]( + /\ channel.mode = ChannelMode.OPEN + /\ channel.turnNumber = AlicesGoalTurnNumber +) + +FinalizedWithLatestTurnNumber == <>[]( + /\ channel.mode = ChannelMode.FINALIZED + /\ channel.turnNumber = LatestTurnNumber +) + +AliceDoesNotLoseFunds == + \/ AliceCanProgressChannel + \/ FinalizedWithLatestTurnNumber ============================================================================= \* Modification History -\* Last modified Tue Aug 27 14:38:51 MDT 2019 by andrewstewart +\* Last modified Tue Aug 27 15:18:25 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 579ad1dca24fb9131fa6446b963ff7f36fa29789 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 27 Aug 2019 23:02:24 -0600 Subject: [PATCH 18/66] Define the checks --- ForceMove/ForceMove.tla | 43 +++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 618af62..335491c 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -5,6 +5,7 @@ CONSTANTS Eve, StartingTurnNumber, NumParticipants, + AlicesIDX, NULL \* A model value representing null. ChannelMode == [ @@ -22,6 +23,7 @@ Names == { Alice, Eve } ASSUME /\ StartingTurnNumber \in Nat /\ NumParticipants \in Nat \ { 1 } + /\ AlicesIDX \in 1..NumParticipants (* --algorithm forceMove @@ -30,14 +32,14 @@ variables challenge = NULL define -mover(turnNumber) == 1 + ((turnNumber-1) % NumParticipants) +alicesMove(turnNumber) == (turnNumber % NumParticipants) = AlicesIDX challengeOngoing == channel.mode = ChannelMode.CHALLENGE -channelOpen == channel.mode = ChannelMode.OPEN - -\* TODO: Fill out these checks. -challengerSigIsValid(challenger) == challenger \in Names -progressesChannel(round) == TRUE -validTransition(turnNumber, signer) == TRUE +channelOpen == channel.mode = ChannelMode.OPEN +challengerSigIsValid(turnNumber, challenger) == + IF alicesMove(turnNumber) + THEN challenge = Alice + ELSE challenger = Eve +progressesChannel(turnNumber) == turnNumber > channel.turnNumber validCommitment(c) == c \in [ turnNumber: Nat ] end define; @@ -87,7 +89,6 @@ begin assert validCommitment(commitment); if /\ channelOpen - /\ challengerSigIsValid(challenger) /\ progressesChannel(commitment.turnNumber) then setChallenge(commitment) end if; @@ -147,7 +148,7 @@ while channel.turnNumber < AlicesGoalTurnNumber do end while; end process; -process eve = Eve +fair process eve = Eve begin (***************************************************************************) (* Eve can do almost anything. *) @@ -182,18 +183,18 @@ end algorithm; \* Label RespondWithMove of process alice at line 139 col 42 changed to RespondWithMove_ \* Label RespondWithAlternativeMove of process alice at line 140 col 53 changed to RespondWithAlternativeMove_ \* Label Refute of process alice at line 141 col 33 changed to Refute_ -\* Label ForceMove of process alice at line 88 col 1 changed to ForceMove_ +\* Label ForceMove of process alice at line 89 col 1 changed to ForceMove_ VARIABLES channel, challenge, pc (* define statement *) -mover(turnNumber) == 1 + ((turnNumber-1) % NumParticipants) +alicesMove(turnNumber) == (turnNumber % NumParticipants) = AlicesIDX challengeOngoing == channel.mode = ChannelMode.CHALLENGE -channelOpen == channel.mode = ChannelMode.OPEN - - -challengerSigIsValid(challenger) == challenger \in Names -progressesChannel(round) == TRUE -validTransition(turnNumber, signer) == TRUE +channelOpen == channel.mode = ChannelMode.OPEN +challengerSigIsValid(turnNumber, challenger) == + IF alicesMove(turnNumber) + THEN challenge = Alice + ELSE challenger = Eve +progressesChannel(turnNumber) == turnNumber > channel.turnNumber validCommitment(c) == c \in [ turnNumber: Nat ] @@ -266,12 +267,11 @@ Refute_ == /\ pc[Alice] = "Refute_" ForceMove_ == /\ pc[Alice] = "ForceMove_" /\ Assert(validCommitment(([ turnNumber |-> LatestTurnNumber ])), - "Failure of assertion at line 88, column 1 of macro called at line 145, column 20.") + "Failure of assertion at line 89, column 1 of macro called at line 145, column 20.") /\ IF /\ channelOpen - /\ challengerSigIsValid(Alice) /\ progressesChannel(([ turnNumber |-> LatestTurnNumber ]).turnNumber) THEN /\ Assert(validCommitment(([ turnNumber |-> LatestTurnNumber ])), - "Failure of assertion at line 54, column 1 of macro called at line 145, column 20.") + "Failure of assertion at line 55, column 1 of macro called at line 145, column 20.") /\ challenge' = [ turnNumber |-> LatestTurnNumber ] ELSE /\ TRUE /\ UNCHANGED challenge @@ -322,6 +322,7 @@ Next == adjudicator \/ alice \/ eve Spec == /\ Init /\ [][Next]_vars /\ WF_vars(adjudicator) /\ WF_vars(alice) + /\ WF_vars(eve) \* END TRANSLATION @@ -355,5 +356,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Tue Aug 27 15:18:25 MDT 2019 by andrewstewart +\* Last modified Tue Aug 27 23:01:47 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 8fd151f1c7ff507a4e035786fe4d70784bffb3c8 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Wed, 28 Aug 2019 11:40:28 -0600 Subject: [PATCH 19/66] Eve can force-move. Start to write alice's responses --- ForceMove/ForceMove.tla | 117 +++++++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 49 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 335491c..e672615 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -41,7 +41,9 @@ challengerSigIsValid(turnNumber, challenger) == ELSE challenger = Eve progressesChannel(turnNumber) == turnNumber > channel.turnNumber validCommitment(c) == c \in [ turnNumber: Nat ] - +validTransition(c, s) == + /\ c.turnNumber = channel.turnNumber + 1 + /\ IF alicesMove(channel.turnNumber) THEN s = Alice ELSE s = Eve end define; macro clearChallenge(commitment) @@ -60,7 +62,7 @@ macro respondWithMove(commitment, signer) begin if /\ challengeOngoing - /\ validTransition(signer, commitment) + /\ validTransition(commitment, signer) then clearChallenge(commitment); end if; end macro; @@ -108,11 +110,9 @@ do \/ challenge # NULL; if challenge = NULL then - FinalizeChannel: assert channel.mode = ChannelMode.CHALLENGE; channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.turnNumber ]; else - RecordChallenge: assert challenge # NULL; channel := [ turnNumber |-> challenge.turnNumber, mode |-> ChannelMode.CHALLENGE ]; challenge := NULL; @@ -136,9 +136,22 @@ AliceMoves: while channel.turnNumber < AlicesGoalTurnNumber do either await channel.mode = ChannelMode.CHALLENGE; - if TRUE then RespondWithMove: skip; - elsif TRUE then RespondWithAlternativeMove: skip; - elsif TRUE then Refute: skip; + if + /\ alicesMove(channel.turnNumber) + /\ channel.turnNumber >= StartingTurnNumber + then + RespondWithMove: + respondWithMove([ turnNumber |-> channel.turnNumber + 1 ], Alice); + elsif FALSE then RespondWithAlternativeMove: skip; + elsif + /\ channel.turnNumber < StartingTurnNumber + then + Refute: + assert ~alicesMove(channel.turnNumber); + \* Alice has signed commitments from StartingTurnNumber up to LastTurnNumber. + \* She can therefore call refute with exactly one commitment, according to + \* the channel's current turnNumber. + skip; \* TODO end if; or await channel.mode = ChannelMode.OPEN; @@ -166,7 +179,10 @@ begin EveMoves: while TRUE do either - ForceMove: skip; + ForceMove: + with n \in NumParticipants..StartingTurnNumber do + forceMove([ turnNumber |-> n ], Eve); + end with; or RespondWithMove: skip; or RespondWithAlternativeMove: skip; or Refute: skip @@ -180,10 +196,9 @@ end algorithm; \* BEGIN TRANSLATION -\* Label RespondWithMove of process alice at line 139 col 42 changed to RespondWithMove_ -\* Label RespondWithAlternativeMove of process alice at line 140 col 53 changed to RespondWithAlternativeMove_ -\* Label Refute of process alice at line 141 col 33 changed to Refute_ -\* Label ForceMove of process alice at line 89 col 1 changed to ForceMove_ +\* Label RespondWithMove of process alice at line 63 col 1 changed to RespondWithMove_ +\* Label Refute of process alice at line 148 col 33 changed to Refute_ +\* Label ForceMove of process alice at line 91 col 1 changed to ForceMove_ VARIABLES channel, challenge, pc (* define statement *) @@ -196,6 +211,9 @@ challengerSigIsValid(turnNumber, challenger) == ELSE challenger = Eve progressesChannel(turnNumber) == turnNumber > channel.turnNumber validCommitment(c) == c \in [ turnNumber: Nat ] +validTransition(c, s) == + /\ c.turnNumber = channel.turnNumber + 1 + /\ IF alicesMove(channel.turnNumber) THEN s = Alice ELSE s = Eve vars == << channel, challenge, pc >> @@ -214,51 +232,44 @@ HandleChallenge == /\ pc["Adjudicator"] = "HandleChallenge" THEN /\ \/ channel.mode = ChannelMode.CHALLENGE \/ challenge # NULL /\ IF challenge = NULL - THEN /\ pc' = [pc EXCEPT !["Adjudicator"] = "FinalizeChannel"] - ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "RecordChallenge"] + THEN /\ Assert(channel.mode = ChannelMode.CHALLENGE, + "Failure of assertion at line 114, column 9.") + /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.turnNumber ] + /\ UNCHANGED challenge + ELSE /\ Assert(challenge # NULL, + "Failure of assertion at line 118, column 9.") + /\ channel' = [ turnNumber |-> challenge.turnNumber, mode |-> ChannelMode.CHALLENGE ] + /\ challenge' = NULL + /\ pc' = [pc EXCEPT !["Adjudicator"] = "HandleChallenge"] ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "Done"] - /\ UNCHANGED << channel, challenge >> - -FinalizeChannel == /\ pc["Adjudicator"] = "FinalizeChannel" - /\ Assert(channel.mode = ChannelMode.CHALLENGE, - "Failure of assertion at line 112, column 9.") - /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.turnNumber ] - /\ pc' = [pc EXCEPT !["Adjudicator"] = "HandleChallenge"] - /\ UNCHANGED challenge - -RecordChallenge == /\ pc["Adjudicator"] = "RecordChallenge" - /\ Assert(challenge # NULL, - "Failure of assertion at line 116, column 9.") - /\ channel' = [ turnNumber |-> challenge.turnNumber, mode |-> ChannelMode.CHALLENGE ] - /\ challenge' = NULL - /\ pc' = [pc EXCEPT !["Adjudicator"] = "HandleChallenge"] + /\ UNCHANGED << channel, challenge >> -adjudicator == HandleChallenge \/ FinalizeChannel \/ RecordChallenge +adjudicator == HandleChallenge AliceMoves == /\ pc[Alice] = "AliceMoves" /\ IF channel.turnNumber < AlicesGoalTurnNumber THEN /\ \/ /\ channel.mode = ChannelMode.CHALLENGE - /\ IF TRUE + /\ IF /\ alicesMove(channel.turnNumber) + /\ channel.turnNumber >= StartingTurnNumber THEN /\ pc' = [pc EXCEPT ![Alice] = "RespondWithMove_"] ELSE /\ IF TRUE - THEN /\ pc' = [pc EXCEPT ![Alice] = "RespondWithAlternativeMove_"] - ELSE /\ IF TRUE - THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute_"] - ELSE /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute_"] + ELSE /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] \/ /\ channel.mode = ChannelMode.OPEN /\ pc' = [pc EXCEPT ![Alice] = "ForceMove_"] ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] /\ UNCHANGED << channel, challenge >> RespondWithMove_ == /\ pc[Alice] = "RespondWithMove_" - /\ TRUE + /\ IF /\ challengeOngoing + /\ validTransition(([ turnNumber |-> channel.turnNumber + 1 ]), Alice) + THEN /\ Assert(validCommitment(([ turnNumber |-> channel.turnNumber + 1 ])), + "Failure of assertion at line 51, column 1 of macro called at line 146, column 17.") + /\ channel' = [ mode |-> ChannelMode.OPEN ] @@ ([ turnNumber |-> channel.turnNumber + 1 ]) + ELSE /\ TRUE + /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED << channel, challenge >> - -RespondWithAlternativeMove_ == /\ pc[Alice] = "RespondWithAlternativeMove_" - /\ TRUE - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED << channel, challenge >> + /\ UNCHANGED challenge Refute_ == /\ pc[Alice] = "Refute_" /\ TRUE @@ -267,19 +278,18 @@ Refute_ == /\ pc[Alice] = "Refute_" ForceMove_ == /\ pc[Alice] = "ForceMove_" /\ Assert(validCommitment(([ turnNumber |-> LatestTurnNumber ])), - "Failure of assertion at line 89, column 1 of macro called at line 145, column 20.") + "Failure of assertion at line 91, column 1 of macro called at line 152, column 20.") /\ IF /\ channelOpen /\ progressesChannel(([ turnNumber |-> LatestTurnNumber ]).turnNumber) THEN /\ Assert(validCommitment(([ turnNumber |-> LatestTurnNumber ])), - "Failure of assertion at line 55, column 1 of macro called at line 145, column 20.") + "Failure of assertion at line 57, column 1 of macro called at line 152, column 20.") /\ challenge' = [ turnNumber |-> LatestTurnNumber ] ELSE /\ TRUE /\ UNCHANGED challenge /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED channel -alice == AliceMoves \/ RespondWithMove_ \/ RespondWithAlternativeMove_ - \/ Refute_ \/ ForceMove_ +alice == AliceMoves \/ RespondWithMove_ \/ Refute_ \/ ForceMove_ EveMoves == /\ pc[Eve] = "EveMoves" /\ \/ /\ pc' = [pc EXCEPT ![Eve] = "ForceMove"] @@ -290,9 +300,18 @@ EveMoves == /\ pc[Eve] = "EveMoves" /\ UNCHANGED << channel, challenge >> ForceMove == /\ pc[Eve] = "ForceMove" - /\ TRUE + /\ \E n \in NumParticipants..StartingTurnNumber: + /\ Assert(validCommitment(([ turnNumber |-> n ])), + "Failure of assertion at line 91, column 1 of macro called at line 178, column 13.") + /\ IF /\ channelOpen + /\ progressesChannel(([ turnNumber |-> n ]).turnNumber) + THEN /\ Assert(validCommitment(([ turnNumber |-> n ])), + "Failure of assertion at line 57, column 1 of macro called at line 178, column 13.") + /\ challenge' = [ turnNumber |-> n ] + ELSE /\ TRUE + /\ UNCHANGED challenge /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] - /\ UNCHANGED << channel, challenge >> + /\ UNCHANGED channel RespondWithMove == /\ pc[Eve] = "RespondWithMove" /\ TRUE @@ -356,5 +375,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Tue Aug 27 23:01:47 MDT 2019 by andrewstewart +\* Last modified Wed Aug 28 11:39:40 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From fdbf6529e8f86edea84a4979e5fdc7f481d80ba2 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Wed, 28 Aug 2019 12:12:07 -0600 Subject: [PATCH 20/66] Add signer to challenges (and channel, when in CHALLENGE Mode) --- ForceMove/ForceMove.tla | 123 ++++++++++++++++++++++------------------ 1 file changed, 69 insertions(+), 54 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index e672615..c0f28f5 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -19,11 +19,12 @@ Range(f) == { f[x] : x \in DOMAIN f } LatestTurnNumber == StartingTurnNumber + NumParticipants - 1 AlicesGoalTurnNumber == LatestTurnNumber + 1 Names == { Alice, Eve } +ParticipantIDXs == 1..NumParticipants ASSUME /\ StartingTurnNumber \in Nat /\ NumParticipants \in Nat \ { 1 } - /\ AlicesIDX \in 1..NumParticipants + /\ AlicesIDX \in ParticipantIDXs (* --algorithm forceMove @@ -40,21 +41,21 @@ challengerSigIsValid(turnNumber, challenger) == THEN challenge = Alice ELSE challenger = Eve progressesChannel(turnNumber) == turnNumber > channel.turnNumber -validCommitment(c) == c \in [ turnNumber: Nat ] +validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(c, s) == /\ c.turnNumber = channel.turnNumber + 1 /\ IF alicesMove(channel.turnNumber) THEN s = Alice ELSE s = Eve end define; -macro clearChallenge(commitment) +macro clearChallenge(turnNumber) begin -assert validCommitment(commitment); -channel := [ mode |-> ChannelMode.OPEN ] @@ commitment; +assert turnNumber \in Nat; +channel := [ mode |-> ChannelMode.OPEN, turnNumber |-> turnNumber ]; end macro; macro setChallenge(commitment) begin -assert validCommitment(commitment); +\*assert validCommitment(commitment); challenge := commitment; end macro; @@ -63,7 +64,7 @@ begin if /\ challengeOngoing /\ validTransition(commitment, signer) -then clearChallenge(commitment); +then clearChallenge(commitment.turnNumber); end if; end macro; @@ -73,20 +74,20 @@ begin if /\ challengeOngoing /\ commitment.turnNumber > channel.turnNumber -then clearChallenge(commitment); +then clearChallenge(commitment.turnNumber); end if; end macro; -macro refute(commitment) +macro refute(turnNumber) begin if /\ challengeOngoing - /\ commitment.turnNumber > channel.turnNumber -then clearChallenge(commitment); + /\ turnNumber > channel.turnNumber +then clearChallenge(channel.turnNumber); end if; end macro; -macro forceMove(commitment, challenger) +macro forceMove(commitment) begin assert validCommitment(commitment); if @@ -114,7 +115,7 @@ do channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.turnNumber ]; else assert challenge # NULL; - channel := [ turnNumber |-> challenge.turnNumber, mode |-> ChannelMode.CHALLENGE ]; + channel := [ mode |-> ChannelMode.CHALLENGE ] @@ challenge; challenge := NULL; end if; end while; @@ -147,15 +148,16 @@ while channel.turnNumber < AlicesGoalTurnNumber do /\ channel.turnNumber < StartingTurnNumber then Refute: - assert ~alicesMove(channel.turnNumber); \* Alice has signed commitments from StartingTurnNumber up to LastTurnNumber. \* She can therefore call refute with exactly one commitment, according to \* the channel's current turnNumber. - skip; \* TODO + \* 1. Get the challenger's idx + \* 2. Refute with the proper turn number + refute(1); end if; or await channel.mode = ChannelMode.OPEN; - ForceMove: forceMove([ turnNumber |-> LatestTurnNumber ], Alice); + ForceMove: forceMove([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]); end either; end while; @@ -180,8 +182,8 @@ EveMoves: while TRUE do either ForceMove: - with n \in NumParticipants..StartingTurnNumber do - forceMove([ turnNumber |-> n ], Eve); + with n \in NumParticipants..StartingTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } do + forceMove([ turnNumber |-> n, signer |-> idx ]); end with; or RespondWithMove: skip; or RespondWithAlternativeMove: skip; @@ -196,9 +198,10 @@ end algorithm; \* BEGIN TRANSLATION -\* Label RespondWithMove of process alice at line 63 col 1 changed to RespondWithMove_ -\* Label Refute of process alice at line 148 col 33 changed to Refute_ -\* Label ForceMove of process alice at line 91 col 1 changed to ForceMove_ +\* Label RespondWithMove of process alice at line 64 col 1 changed to RespondWithMove_ +\* Label RespondWithAlternativeMove of process alice at line 146 col 54 changed to RespondWithAlternativeMove_ +\* Label Refute of process alice at line 83 col 1 changed to Refute_ +\* Label ForceMove of process alice at line 92 col 1 changed to ForceMove_ VARIABLES channel, challenge, pc (* define statement *) @@ -210,7 +213,7 @@ challengerSigIsValid(turnNumber, challenger) == THEN challenge = Alice ELSE challenger = Eve progressesChannel(turnNumber) == turnNumber > channel.turnNumber -validCommitment(c) == c \in [ turnNumber: Nat ] +validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(c, s) == /\ c.turnNumber = channel.turnNumber + 1 /\ IF alicesMove(channel.turnNumber) THEN s = Alice ELSE s = Eve @@ -237,8 +240,8 @@ HandleChallenge == /\ pc["Adjudicator"] = "HandleChallenge" /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.turnNumber ] /\ UNCHANGED challenge ELSE /\ Assert(challenge # NULL, - "Failure of assertion at line 118, column 9.") - /\ channel' = [ turnNumber |-> challenge.turnNumber, mode |-> ChannelMode.CHALLENGE ] + "Failure of assertion at line 117, column 9.") + /\ channel' = [ mode |-> ChannelMode.CHALLENGE ] @@ challenge /\ challenge' = NULL /\ pc' = [pc EXCEPT !["Adjudicator"] = "HandleChallenge"] ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "Done"] @@ -252,9 +255,11 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" /\ IF /\ alicesMove(channel.turnNumber) /\ channel.turnNumber >= StartingTurnNumber THEN /\ pc' = [pc EXCEPT ![Alice] = "RespondWithMove_"] - ELSE /\ IF TRUE - THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute_"] - ELSE /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + ELSE /\ IF FALSE + THEN /\ pc' = [pc EXCEPT ![Alice] = "RespondWithAlternativeMove_"] + ELSE /\ IF /\ channel.turnNumber < StartingTurnNumber + THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute_"] + ELSE /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] \/ /\ channel.mode = ChannelMode.OPEN /\ pc' = [pc EXCEPT ![Alice] = "ForceMove_"] ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] @@ -263,33 +268,43 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" RespondWithMove_ == /\ pc[Alice] = "RespondWithMove_" /\ IF /\ challengeOngoing /\ validTransition(([ turnNumber |-> channel.turnNumber + 1 ]), Alice) - THEN /\ Assert(validCommitment(([ turnNumber |-> channel.turnNumber + 1 ])), - "Failure of assertion at line 51, column 1 of macro called at line 146, column 17.") - /\ channel' = [ mode |-> ChannelMode.OPEN ] @@ ([ turnNumber |-> channel.turnNumber + 1 ]) + THEN /\ Assert((([ turnNumber |-> channel.turnNumber + 1 ]).turnNumber) \in Nat, + "Failure of assertion at line 52, column 1 of macro called at line 145, column 17.") + /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (([ turnNumber |-> channel.turnNumber + 1 ]).turnNumber) ] ELSE /\ TRUE /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED challenge +RespondWithAlternativeMove_ == /\ pc[Alice] = "RespondWithAlternativeMove_" + /\ TRUE + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + /\ UNCHANGED << channel, challenge >> + Refute_ == /\ pc[Alice] = "Refute_" - /\ TRUE + /\ IF /\ challengeOngoing + /\ 1 > channel.turnNumber + THEN /\ Assert((channel.turnNumber) \in Nat, + "Failure of assertion at line 52, column 1 of macro called at line 156, column 17.") + /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (channel.turnNumber) ] + ELSE /\ TRUE + /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED << channel, challenge >> + /\ UNCHANGED challenge ForceMove_ == /\ pc[Alice] = "ForceMove_" - /\ Assert(validCommitment(([ turnNumber |-> LatestTurnNumber ])), - "Failure of assertion at line 91, column 1 of macro called at line 152, column 20.") + /\ Assert(validCommitment(([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ])), + "Failure of assertion at line 92, column 1 of macro called at line 160, column 20.") /\ IF /\ channelOpen - /\ progressesChannel(([ turnNumber |-> LatestTurnNumber ]).turnNumber) - THEN /\ Assert(validCommitment(([ turnNumber |-> LatestTurnNumber ])), - "Failure of assertion at line 57, column 1 of macro called at line 152, column 20.") - /\ challenge' = [ turnNumber |-> LatestTurnNumber ] + /\ progressesChannel(([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]).turnNumber) + THEN /\ challenge' = [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ] ELSE /\ TRUE /\ UNCHANGED challenge /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED channel -alice == AliceMoves \/ RespondWithMove_ \/ Refute_ \/ ForceMove_ +alice == AliceMoves \/ RespondWithMove_ \/ RespondWithAlternativeMove_ + \/ Refute_ \/ ForceMove_ EveMoves == /\ pc[Eve] = "EveMoves" /\ \/ /\ pc' = [pc EXCEPT ![Eve] = "ForceMove"] @@ -301,15 +316,14 @@ EveMoves == /\ pc[Eve] = "EveMoves" ForceMove == /\ pc[Eve] = "ForceMove" /\ \E n \in NumParticipants..StartingTurnNumber: - /\ Assert(validCommitment(([ turnNumber |-> n ])), - "Failure of assertion at line 91, column 1 of macro called at line 178, column 13.") - /\ IF /\ channelOpen - /\ progressesChannel(([ turnNumber |-> n ]).turnNumber) - THEN /\ Assert(validCommitment(([ turnNumber |-> n ])), - "Failure of assertion at line 57, column 1 of macro called at line 178, column 13.") - /\ challenge' = [ turnNumber |-> n ] - ELSE /\ TRUE - /\ UNCHANGED challenge + \E idx \in ParticipantIDXs \ { AlicesIDX }: + /\ Assert(validCommitment(([ turnNumber |-> n, signer |-> idx ])), + "Failure of assertion at line 92, column 1 of macro called at line 186, column 13.") + /\ IF /\ channelOpen + /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ]).turnNumber) + THEN /\ challenge' = [ turnNumber |-> n, signer |-> idx ] + ELSE /\ TRUE + /\ UNCHANGED challenge /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] /\ UNCHANGED channel @@ -346,17 +360,18 @@ Spec == /\ Init /\ [][Next]_vars \* END TRANSLATION AllowedTurnNumbers == 0..(StartingTurnNumber + NumParticipants) -AllowedChannels == - [ - turnNumber: AllowedTurnNumbers, - mode: Range(ChannelMode) - ] +AllowedChannels == {} + \cup [ turnNumber: AllowedTurnNumbers, mode: { ChannelMode.OPEN, ChannelMode.FINALIZED } ] + \cup [ turnNumber: AllowedTurnNumbers, mode: { ChannelMode.CHALLENGE }, signer: ParticipantIDXs ] +AllowedChallenges == { NULL } + \cup [ turnNumber: AllowedTurnNumbers, signer: ParticipantIDXs ] \* Safety properties TypeOK == /\ channel \in AllowedChannels + /\ challenge \in AllowedChallenges \* Liveness properties AliceCanProgressChannel == <>[]( @@ -375,5 +390,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Wed Aug 28 11:39:40 MDT 2019 by andrewstewart +\* Last modified Wed Aug 28 12:11:37 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 2ac20ac81e35cbce3860d57b9a679ebf759503e2 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Wed, 28 Aug 2019 12:52:10 -0600 Subject: [PATCH 21/66] Alice refutes properly. She finalizes the channel when she cannot clear a challenge --- ForceMove/ForceMove.tla | 223 +++++++++++++++++++--------------------- 1 file changed, 108 insertions(+), 115 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index c0f28f5..f958e9b 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -20,6 +20,7 @@ LatestTurnNumber == StartingTurnNumber + NumParticipants - 1 AlicesGoalTurnNumber == LatestTurnNumber + 1 Names == { Alice, Eve } ParticipantIDXs == 1..NumParticipants +AlicesCommitments == StartingTurnNumber..LatestTurnNumber ASSUME /\ StartingTurnNumber \in Nat @@ -40,7 +41,7 @@ challengerSigIsValid(turnNumber, challenger) == IF alicesMove(turnNumber) THEN challenge = Alice ELSE challenger = Eve -progressesChannel(turnNumber) == turnNumber > channel.turnNumber +progressesChannel(turnNumber) == turnNumber >= channel.turnNumber validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(c, s) == /\ c.turnNumber = channel.turnNumber + 1 @@ -101,20 +102,12 @@ end macro; fair process adjudicator = "Adjudicator" begin (***************************************************************************) -(* This process expires active channels and records submitted *) -(* channels. *) +(* This process records submitted channels. *) (***************************************************************************) -HandleChallenge: +Adjudicator: while channel.mode # ChannelMode.FINALIZED -do - await \/ channel.mode = ChannelMode.CHALLENGE - \/ challenge # NULL; - if challenge = NULL - then - assert channel.mode = ChannelMode.CHALLENGE; - channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.turnNumber ]; - else - assert challenge # NULL; +do HandleChallenge: + if challenge # NULL then channel := [ mode |-> ChannelMode.CHALLENGE ] @@ challenge; challenge := NULL; end if; @@ -134,32 +127,35 @@ begin (* challenge where it's her turn to move *) (***************************************************************************) AliceMoves: -while channel.turnNumber < AlicesGoalTurnNumber do - either - await channel.mode = ChannelMode.CHALLENGE; +while + /\ channel.turnNumber < AlicesGoalTurnNumber + /\ channel.mode # ChannelMode.FINALIZED +do + if channel.mode = ChannelMode.CHALLENGE then if /\ alicesMove(channel.turnNumber) /\ channel.turnNumber >= StartingTurnNumber - then - RespondWithMove: - respondWithMove([ turnNumber |-> channel.turnNumber + 1 ], Alice); - elsif FALSE then RespondWithAlternativeMove: skip; + then respondWithMove([ turnNumber |-> channel.turnNumber + 1 ], Alice); + elsif FALSE then skip; elsif /\ channel.turnNumber < StartingTurnNumber then - Refute: - \* Alice has signed commitments from StartingTurnNumber up to LastTurnNumber. - \* She can therefore call refute with exactly one commitment, according to - \* the channel's current turnNumber. - \* 1. Get the challenger's idx - \* 2. Refute with the proper turn number - refute(1); + \* Alice has signed commitments from StartingTurnNumber up to LastTurnNumber. + \* She can therefore call refute with exactly one commitment, according to + \* the channel's current turnNumber. + \* 1. Get the challenger's idx + \* 2. Refute with the proper turn number + refute(CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.signer % NumParticipants); end if; - or - await channel.mode = ChannelMode.OPEN; - ForceMove: forceMove([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]); - end either; - + + \* If the challenge wasn't cleared, then Alice's strategy has failed, finalizing the channel. + if channel.mode = ChannelMode.CHALLENGE then + FinalizeChannel: + channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.turnNumber ]; + end if; + elsif challenge = NULL then + forceMove([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]); + end if; end while; end process; @@ -179,7 +175,7 @@ begin (* challenge to expire. *) (***************************************************************************) EveMoves: -while TRUE do +while channel.mode # ChannelMode.FINALIZED do either ForceMove: with n \in NumParticipants..StartingTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } do @@ -198,10 +194,6 @@ end algorithm; \* BEGIN TRANSLATION -\* Label RespondWithMove of process alice at line 64 col 1 changed to RespondWithMove_ -\* Label RespondWithAlternativeMove of process alice at line 146 col 54 changed to RespondWithAlternativeMove_ -\* Label Refute of process alice at line 83 col 1 changed to Refute_ -\* Label ForceMove of process alice at line 92 col 1 changed to ForceMove_ VARIABLES channel, challenge, pc (* define statement *) @@ -212,7 +204,7 @@ challengerSigIsValid(turnNumber, challenger) == IF alicesMove(turnNumber) THEN challenge = Alice ELSE challenger = Eve -progressesChannel(turnNumber) == turnNumber > channel.turnNumber +progressesChannel(turnNumber) == turnNumber >= channel.turnNumber validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(c, s) == /\ c.turnNumber = channel.turnNumber + 1 @@ -226,99 +218,93 @@ ProcSet == {"Adjudicator"} \cup {Alice} \cup {Eve} Init == (* Global variables *) /\ channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN ] /\ challenge = NULL - /\ pc = [self \in ProcSet |-> CASE self = "Adjudicator" -> "HandleChallenge" + /\ pc = [self \in ProcSet |-> CASE self = "Adjudicator" -> "Adjudicator" [] self = Alice -> "AliceMoves" [] self = Eve -> "EveMoves"] +Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" + /\ IF channel.mode # ChannelMode.FINALIZED + THEN /\ pc' = [pc EXCEPT !["Adjudicator"] = "HandleChallenge"] + ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "Done"] + /\ UNCHANGED << channel, challenge >> + HandleChallenge == /\ pc["Adjudicator"] = "HandleChallenge" - /\ IF channel.mode # ChannelMode.FINALIZED - THEN /\ \/ channel.mode = ChannelMode.CHALLENGE - \/ challenge # NULL - /\ IF challenge = NULL - THEN /\ Assert(channel.mode = ChannelMode.CHALLENGE, - "Failure of assertion at line 114, column 9.") - /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.turnNumber ] - /\ UNCHANGED challenge - ELSE /\ Assert(challenge # NULL, - "Failure of assertion at line 117, column 9.") - /\ channel' = [ mode |-> ChannelMode.CHALLENGE ] @@ challenge - /\ challenge' = NULL - /\ pc' = [pc EXCEPT !["Adjudicator"] = "HandleChallenge"] - ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "Done"] + /\ IF challenge # NULL + THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE ] @@ challenge + /\ challenge' = NULL + ELSE /\ TRUE /\ UNCHANGED << channel, challenge >> + /\ pc' = [pc EXCEPT !["Adjudicator"] = "Adjudicator"] -adjudicator == HandleChallenge +adjudicator == Adjudicator \/ HandleChallenge AliceMoves == /\ pc[Alice] = "AliceMoves" - /\ IF channel.turnNumber < AlicesGoalTurnNumber - THEN /\ \/ /\ channel.mode = ChannelMode.CHALLENGE - /\ IF /\ alicesMove(channel.turnNumber) - /\ channel.turnNumber >= StartingTurnNumber - THEN /\ pc' = [pc EXCEPT ![Alice] = "RespondWithMove_"] - ELSE /\ IF FALSE - THEN /\ pc' = [pc EXCEPT ![Alice] = "RespondWithAlternativeMove_"] - ELSE /\ IF /\ channel.turnNumber < StartingTurnNumber - THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute_"] - ELSE /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - \/ /\ channel.mode = ChannelMode.OPEN - /\ pc' = [pc EXCEPT ![Alice] = "ForceMove_"] + /\ IF /\ channel.turnNumber < AlicesGoalTurnNumber + /\ channel.mode # ChannelMode.FINALIZED + THEN /\ IF channel.mode = ChannelMode.CHALLENGE + THEN /\ IF /\ alicesMove(channel.turnNumber) + /\ channel.turnNumber >= StartingTurnNumber + THEN /\ IF /\ challengeOngoing + /\ validTransition(([ turnNumber |-> channel.turnNumber + 1 ]), Alice) + THEN /\ Assert((([ turnNumber |-> channel.turnNumber + 1 ]).turnNumber) \in Nat, + "Failure of assertion at line 53, column 1 of macro called at line 138, column 14.") + /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (([ turnNumber |-> channel.turnNumber + 1 ]).turnNumber) ] + ELSE /\ TRUE + /\ UNCHANGED channel + ELSE /\ IF FALSE + THEN /\ TRUE + /\ UNCHANGED channel + ELSE /\ IF /\ channel.turnNumber < StartingTurnNumber + THEN /\ IF /\ challengeOngoing + /\ (CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.signer % NumParticipants) > channel.turnNumber + THEN /\ Assert((channel.turnNumber) \in Nat, + "Failure of assertion at line 53, column 1 of macro called at line 148, column 13.") + /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (channel.turnNumber) ] + ELSE /\ TRUE + /\ UNCHANGED channel + ELSE /\ TRUE + /\ UNCHANGED channel + /\ IF channel'.mode = ChannelMode.CHALLENGE + THEN /\ pc' = [pc EXCEPT ![Alice] = "FinalizeChannel"] + ELSE /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + /\ UNCHANGED challenge + ELSE /\ IF challenge = NULL + THEN /\ Assert(validCommitment(([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ])), + "Failure of assertion at line 93, column 1 of macro called at line 157, column 9.") + /\ IF /\ channelOpen + /\ progressesChannel(([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]).turnNumber) + THEN /\ challenge' = [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ] + ELSE /\ TRUE + /\ UNCHANGED challenge + ELSE /\ TRUE + /\ UNCHANGED challenge + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + /\ UNCHANGED channel ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] - /\ UNCHANGED << channel, challenge >> - -RespondWithMove_ == /\ pc[Alice] = "RespondWithMove_" - /\ IF /\ challengeOngoing - /\ validTransition(([ turnNumber |-> channel.turnNumber + 1 ]), Alice) - THEN /\ Assert((([ turnNumber |-> channel.turnNumber + 1 ]).turnNumber) \in Nat, - "Failure of assertion at line 52, column 1 of macro called at line 145, column 17.") - /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (([ turnNumber |-> channel.turnNumber + 1 ]).turnNumber) ] - ELSE /\ TRUE - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED challenge - -RespondWithAlternativeMove_ == /\ pc[Alice] = "RespondWithAlternativeMove_" - /\ TRUE - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED << channel, challenge >> - -Refute_ == /\ pc[Alice] = "Refute_" - /\ IF /\ challengeOngoing - /\ 1 > channel.turnNumber - THEN /\ Assert((channel.turnNumber) \in Nat, - "Failure of assertion at line 52, column 1 of macro called at line 156, column 17.") - /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (channel.turnNumber) ] - ELSE /\ TRUE - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED challenge - -ForceMove_ == /\ pc[Alice] = "ForceMove_" - /\ Assert(validCommitment(([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ])), - "Failure of assertion at line 92, column 1 of macro called at line 160, column 20.") - /\ IF /\ channelOpen - /\ progressesChannel(([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]).turnNumber) - THEN /\ challenge' = [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ] - ELSE /\ TRUE - /\ UNCHANGED challenge - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED channel - -alice == AliceMoves \/ RespondWithMove_ \/ RespondWithAlternativeMove_ - \/ Refute_ \/ ForceMove_ + /\ UNCHANGED << channel, challenge >> + +FinalizeChannel == /\ pc[Alice] = "FinalizeChannel" + /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.turnNumber ] + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + /\ UNCHANGED challenge + +alice == AliceMoves \/ FinalizeChannel EveMoves == /\ pc[Eve] = "EveMoves" - /\ \/ /\ pc' = [pc EXCEPT ![Eve] = "ForceMove"] - \/ /\ pc' = [pc EXCEPT ![Eve] = "RespondWithMove"] - \/ /\ pc' = [pc EXCEPT ![Eve] = "RespondWithAlternativeMove"] - \/ /\ pc' = [pc EXCEPT ![Eve] = "Refute"] - \/ /\ pc' = [pc EXCEPT ![Eve] = "Sleep"] + /\ IF channel.mode # ChannelMode.FINALIZED + THEN /\ \/ /\ pc' = [pc EXCEPT ![Eve] = "ForceMove"] + \/ /\ pc' = [pc EXCEPT ![Eve] = "RespondWithMove"] + \/ /\ pc' = [pc EXCEPT ![Eve] = "RespondWithAlternativeMove"] + \/ /\ pc' = [pc EXCEPT ![Eve] = "Refute"] + \/ /\ pc' = [pc EXCEPT ![Eve] = "Sleep"] + ELSE /\ pc' = [pc EXCEPT ![Eve] = "Done"] /\ UNCHANGED << channel, challenge >> ForceMove == /\ pc[Eve] = "ForceMove" /\ \E n \in NumParticipants..StartingTurnNumber: \E idx \in ParticipantIDXs \ { AlicesIDX }: /\ Assert(validCommitment(([ turnNumber |-> n, signer |-> idx ])), - "Failure of assertion at line 92, column 1 of macro called at line 186, column 13.") + "Failure of assertion at line 93, column 1 of macro called at line 182, column 13.") /\ IF /\ channelOpen /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ]).turnNumber) THEN /\ challenge' = [ turnNumber |-> n, signer |-> idx ] @@ -350,13 +336,20 @@ Sleep == /\ pc[Eve] = "Sleep" eve == EveMoves \/ ForceMove \/ RespondWithMove \/ RespondWithAlternativeMove \/ Refute \/ Sleep +(* Allow infinite stuttering to prevent deadlock on termination. *) +Terminating == /\ \A self \in ProcSet: pc[self] = "Done" + /\ UNCHANGED vars + Next == adjudicator \/ alice \/ eve + \/ Terminating Spec == /\ Init /\ [][Next]_vars /\ WF_vars(adjudicator) /\ WF_vars(alice) /\ WF_vars(eve) +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + \* END TRANSLATION AllowedTurnNumbers == 0..(StartingTurnNumber + NumParticipants) @@ -390,5 +383,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Wed Aug 28 12:11:37 MDT 2019 by andrewstewart +\* Last modified Wed Aug 28 12:51:37 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 5e47ded4218ca61e1645b97c8fafa6f1ab020440 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Wed, 28 Aug 2019 12:52:34 -0600 Subject: [PATCH 22/66] Fix ProgressesChannel --- ForceMove/ForceMove.tla | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index f958e9b..b19f676 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -41,7 +41,7 @@ challengerSigIsValid(turnNumber, challenger) == IF alicesMove(turnNumber) THEN challenge = Alice ELSE challenger = Eve -progressesChannel(turnNumber) == turnNumber >= channel.turnNumber +progressesChannel(turnNumber) == turnNumber > channel.turnNumber validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(c, s) == /\ c.turnNumber = channel.turnNumber + 1 @@ -204,7 +204,7 @@ challengerSigIsValid(turnNumber, challenger) == IF alicesMove(turnNumber) THEN challenge = Alice ELSE challenger = Eve -progressesChannel(turnNumber) == turnNumber >= channel.turnNumber +progressesChannel(turnNumber) == turnNumber > channel.turnNumber validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(c, s) == /\ c.turnNumber = channel.turnNumber + 1 @@ -383,5 +383,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Wed Aug 28 12:51:37 MDT 2019 by andrewstewart +\* Last modified Wed Aug 28 12:52:17 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 1dc630b010014a79f1d46e021fc61aa428291afb Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Wed, 28 Aug 2019 13:56:55 -0600 Subject: [PATCH 23/66] Store challenge on channel rather than update turn number --- ForceMove/ForceMove.tla | 158 ++++++++++++++++++++++------------------ 1 file changed, 87 insertions(+), 71 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index b19f676..1256178 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -21,11 +21,13 @@ AlicesGoalTurnNumber == LatestTurnNumber + 1 Names == { Alice, Eve } ParticipantIDXs == 1..NumParticipants AlicesCommitments == StartingTurnNumber..LatestTurnNumber +AlicesMove(turnNumber) == (turnNumber + 1) % NumParticipants = AlicesIDX % NumParticipants ASSUME /\ StartingTurnNumber \in Nat /\ NumParticipants \in Nat \ { 1 } /\ AlicesIDX \in ParticipantIDXs + /\ ~AlicesMove(LatestTurnNumber) (* --algorithm forceMove @@ -34,18 +36,23 @@ variables challenge = NULL define -alicesMove(turnNumber) == (turnNumber % NumParticipants) = AlicesIDX challengeOngoing == channel.mode = ChannelMode.CHALLENGE channelOpen == channel.mode = ChannelMode.OPEN challengerSigIsValid(turnNumber, challenger) == - IF alicesMove(turnNumber) + IF AlicesMove(turnNumber) THEN challenge = Alice ELSE challenger = Eve progressesChannel(turnNumber) == turnNumber > channel.turnNumber validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(c, s) == /\ c.turnNumber = channel.turnNumber + 1 - /\ IF alicesMove(channel.turnNumber) THEN s = Alice ELSE s = Eve + /\ IF AlicesMove(channel.turnNumber) THEN s = Alice ELSE s = Eve + +AliceCanTakeAction == + \/ /\ AlicesMove(channel.turnNumber) + /\ channel.turnNumber = LatestTurnNumber + \/ channel.mode # ChannelMode.FINALIZED + end define; macro clearChallenge(turnNumber) @@ -105,10 +112,10 @@ begin (* This process records submitted channels. *) (***************************************************************************) Adjudicator: -while channel.mode # ChannelMode.FINALIZED +while AliceCanTakeAction do HandleChallenge: if challenge # NULL then - channel := [ mode |-> ChannelMode.CHALLENGE ] @@ challenge; + channel := [ mode |-> ChannelMode.CHALLENGE, challenge |-> challenge ] @@ channel; challenge := NULL; end if; end while; @@ -127,15 +134,13 @@ begin (* challenge where it's her turn to move *) (***************************************************************************) AliceMoves: -while - /\ channel.turnNumber < AlicesGoalTurnNumber - /\ channel.mode # ChannelMode.FINALIZED +while AliceCanTakeAction do if channel.mode = ChannelMode.CHALLENGE then if - /\ alicesMove(channel.turnNumber) - /\ channel.turnNumber >= StartingTurnNumber - then respondWithMove([ turnNumber |-> channel.turnNumber + 1 ], Alice); + /\ AlicesMove(channel.challenge.turnNumber) + /\ channel.challenge.turnNumber >= StartingTurnNumber + then Respond: respondWithMove([ turnNumber |-> channel.turnNumber + 1 ], Alice); elsif FALSE then skip; elsif /\ channel.turnNumber < StartingTurnNumber @@ -143,18 +148,16 @@ do \* Alice has signed commitments from StartingTurnNumber up to LastTurnNumber. \* She can therefore call refute with exactly one commitment, according to \* the channel's current turnNumber. - \* 1. Get the challenger's idx - \* 2. Refute with the proper turn number - refute(CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.signer % NumParticipants); + Refute: refute(CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.challenge.signer % NumParticipants); end if; - + FinalizeChannel: \* If the challenge wasn't cleared, then Alice's strategy has failed, finalizing the channel. if channel.mode = ChannelMode.CHALLENGE then - FinalizeChannel: - channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.turnNumber ]; + channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.challenge.turnNumber - 1 ]; end if; elsif challenge = NULL then - forceMove([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]); + ForceMove: + forceMove([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ]); end if; end while; end process; @@ -175,7 +178,7 @@ begin (* challenge to expire. *) (***************************************************************************) EveMoves: -while channel.mode # ChannelMode.FINALIZED do +while AliceCanTakeAction do either ForceMove: with n \in NumParticipants..StartingTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } do @@ -194,21 +197,27 @@ end algorithm; \* BEGIN TRANSLATION +\* Label Refute of process alice at line 91 col 1 changed to Refute_ +\* Label ForceMove of process alice at line 100 col 1 changed to ForceMove_ VARIABLES channel, challenge, pc (* define statement *) -alicesMove(turnNumber) == (turnNumber % NumParticipants) = AlicesIDX challengeOngoing == channel.mode = ChannelMode.CHALLENGE channelOpen == channel.mode = ChannelMode.OPEN challengerSigIsValid(turnNumber, challenger) == - IF alicesMove(turnNumber) + IF AlicesMove(turnNumber) THEN challenge = Alice ELSE challenger = Eve progressesChannel(turnNumber) == turnNumber > channel.turnNumber validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(c, s) == /\ c.turnNumber = channel.turnNumber + 1 - /\ IF alicesMove(channel.turnNumber) THEN s = Alice ELSE s = Eve + /\ IF AlicesMove(channel.turnNumber) THEN s = Alice ELSE s = Eve + +AliceCanTakeAction == + \/ /\ AlicesMove(channel.turnNumber) + /\ channel.turnNumber = LatestTurnNumber + \/ channel.mode # ChannelMode.FINALIZED vars == << channel, challenge, pc >> @@ -223,14 +232,14 @@ Init == (* Global variables *) [] self = Eve -> "EveMoves"] Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" - /\ IF channel.mode # ChannelMode.FINALIZED + /\ IF AliceCanTakeAction THEN /\ pc' = [pc EXCEPT !["Adjudicator"] = "HandleChallenge"] ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "Done"] /\ UNCHANGED << channel, challenge >> HandleChallenge == /\ pc["Adjudicator"] = "HandleChallenge" /\ IF challenge # NULL - THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE ] @@ challenge + THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> challenge ] @@ channel /\ challenge' = NULL ELSE /\ TRUE /\ UNCHANGED << channel, challenge >> @@ -239,59 +248,68 @@ HandleChallenge == /\ pc["Adjudicator"] = "HandleChallenge" adjudicator == Adjudicator \/ HandleChallenge AliceMoves == /\ pc[Alice] = "AliceMoves" - /\ IF /\ channel.turnNumber < AlicesGoalTurnNumber - /\ channel.mode # ChannelMode.FINALIZED + /\ IF AliceCanTakeAction THEN /\ IF channel.mode = ChannelMode.CHALLENGE - THEN /\ IF /\ alicesMove(channel.turnNumber) - /\ channel.turnNumber >= StartingTurnNumber - THEN /\ IF /\ challengeOngoing - /\ validTransition(([ turnNumber |-> channel.turnNumber + 1 ]), Alice) - THEN /\ Assert((([ turnNumber |-> channel.turnNumber + 1 ]).turnNumber) \in Nat, - "Failure of assertion at line 53, column 1 of macro called at line 138, column 14.") - /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (([ turnNumber |-> channel.turnNumber + 1 ]).turnNumber) ] - ELSE /\ TRUE - /\ UNCHANGED channel + THEN /\ IF /\ AlicesMove(channel.challenge.turnNumber) + /\ channel.challenge.turnNumber >= StartingTurnNumber + THEN /\ pc' = [pc EXCEPT ![Alice] = "Respond"] ELSE /\ IF FALSE THEN /\ TRUE - /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![Alice] = "FinalizeChannel"] ELSE /\ IF /\ channel.turnNumber < StartingTurnNumber - THEN /\ IF /\ challengeOngoing - /\ (CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.signer % NumParticipants) > channel.turnNumber - THEN /\ Assert((channel.turnNumber) \in Nat, - "Failure of assertion at line 53, column 1 of macro called at line 148, column 13.") - /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (channel.turnNumber) ] - ELSE /\ TRUE - /\ UNCHANGED channel - ELSE /\ TRUE - /\ UNCHANGED channel - /\ IF channel'.mode = ChannelMode.CHALLENGE - THEN /\ pc' = [pc EXCEPT ![Alice] = "FinalizeChannel"] - ELSE /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED challenge + THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute_"] + ELSE /\ pc' = [pc EXCEPT ![Alice] = "FinalizeChannel"] ELSE /\ IF challenge = NULL - THEN /\ Assert(validCommitment(([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ])), - "Failure of assertion at line 93, column 1 of macro called at line 157, column 9.") - /\ IF /\ channelOpen - /\ progressesChannel(([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]).turnNumber) - THEN /\ challenge' = [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ] - ELSE /\ TRUE - /\ UNCHANGED challenge - ELSE /\ TRUE - /\ UNCHANGED challenge - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED channel + THEN /\ pc' = [pc EXCEPT ![Alice] = "ForceMove_"] + ELSE /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] - /\ UNCHANGED << channel, challenge >> + /\ UNCHANGED << channel, challenge >> FinalizeChannel == /\ pc[Alice] = "FinalizeChannel" - /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.turnNumber ] + /\ IF channel.mode = ChannelMode.CHALLENGE + THEN /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.challenge.turnNumber - 1 ] + ELSE /\ TRUE + /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED challenge -alice == AliceMoves \/ FinalizeChannel +Respond == /\ pc[Alice] = "Respond" + /\ IF /\ challengeOngoing + /\ validTransition(([ turnNumber |-> channel.turnNumber + 1 ]), Alice) + THEN /\ Assert((([ turnNumber |-> channel.turnNumber + 1 ]).turnNumber) \in Nat, + "Failure of assertion at line 60, column 1 of macro called at line 143, column 23.") + /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (([ turnNumber |-> channel.turnNumber + 1 ]).turnNumber) ] + ELSE /\ TRUE + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![Alice] = "FinalizeChannel"] + /\ UNCHANGED challenge + +Refute_ == /\ pc[Alice] = "Refute_" + /\ IF /\ challengeOngoing + /\ (CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.challenge.signer % NumParticipants) > channel.turnNumber + THEN /\ Assert((channel.turnNumber) \in Nat, + "Failure of assertion at line 60, column 1 of macro called at line 151, column 21.") + /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (channel.turnNumber) ] + ELSE /\ TRUE + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![Alice] = "FinalizeChannel"] + /\ UNCHANGED challenge + +ForceMove_ == /\ pc[Alice] = "ForceMove_" + /\ Assert(validCommitment(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ])), + "Failure of assertion at line 100, column 1 of macro called at line 160, column 9.") + /\ IF /\ channelOpen + /\ progressesChannel(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ]).turnNumber) + THEN /\ challenge' = [ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ] + ELSE /\ TRUE + /\ UNCHANGED challenge + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + /\ UNCHANGED channel + +alice == AliceMoves \/ FinalizeChannel \/ Respond \/ Refute_ \/ ForceMove_ EveMoves == /\ pc[Eve] = "EveMoves" - /\ IF channel.mode # ChannelMode.FINALIZED + /\ IF AliceCanTakeAction THEN /\ \/ /\ pc' = [pc EXCEPT ![Eve] = "ForceMove"] \/ /\ pc' = [pc EXCEPT ![Eve] = "RespondWithMove"] \/ /\ pc' = [pc EXCEPT ![Eve] = "RespondWithAlternativeMove"] @@ -304,7 +322,7 @@ ForceMove == /\ pc[Eve] = "ForceMove" /\ \E n \in NumParticipants..StartingTurnNumber: \E idx \in ParticipantIDXs \ { AlicesIDX }: /\ Assert(validCommitment(([ turnNumber |-> n, signer |-> idx ])), - "Failure of assertion at line 93, column 1 of macro called at line 182, column 13.") + "Failure of assertion at line 100, column 1 of macro called at line 185, column 13.") /\ IF /\ channelOpen /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ]).turnNumber) THEN /\ challenge' = [ turnNumber |-> n, signer |-> idx ] @@ -353,18 +371,16 @@ Termination == <>(\A self \in ProcSet: pc[self] = "Done") \* END TRANSLATION AllowedTurnNumbers == 0..(StartingTurnNumber + NumParticipants) +AllowedChallenges == [ turnNumber: AllowedTurnNumbers, signer: ParticipantIDXs ] AllowedChannels == {} \cup [ turnNumber: AllowedTurnNumbers, mode: { ChannelMode.OPEN, ChannelMode.FINALIZED } ] - \cup [ turnNumber: AllowedTurnNumbers, mode: { ChannelMode.CHALLENGE }, signer: ParticipantIDXs ] -AllowedChallenges == { NULL } - \cup [ turnNumber: AllowedTurnNumbers, signer: ParticipantIDXs ] - + \cup [ turnNumber: AllowedTurnNumbers, mode: { ChannelMode.CHALLENGE }, challenge: AllowedChallenges ] \* Safety properties TypeOK == /\ channel \in AllowedChannels - /\ challenge \in AllowedChallenges + /\ challenge \in { NULL } \cup AllowedChallenges \* Liveness properties AliceCanProgressChannel == <>[]( @@ -383,5 +399,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Wed Aug 28 12:52:17 MDT 2019 by andrewstewart +\* Last modified Wed Aug 28 13:55:59 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From fb57dfa10b81b24e310fa9aca143c3a8b9e9e50a Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Wed, 28 Aug 2019 14:20:00 -0600 Subject: [PATCH 24/66] Correct turn number checks --- ForceMove/ForceMove.tla | 167 ++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 100 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 1256178..c8fe782 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -44,9 +44,9 @@ challengerSigIsValid(turnNumber, challenger) == ELSE challenger = Eve progressesChannel(turnNumber) == turnNumber > channel.turnNumber validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] -validTransition(c, s) == - /\ c.turnNumber = channel.turnNumber + 1 - /\ IF AlicesMove(channel.turnNumber) THEN s = Alice ELSE s = Eve +validTransition(commitment) == + /\ commitment.turnNumber = channel.challenge.turnNumber + 1 + /\ commitment.turnNumber % NumParticipants = commitment.signer % NumParticipants AliceCanTakeAction == \/ /\ AlicesMove(channel.turnNumber) @@ -67,16 +67,19 @@ begin challenge := commitment; end macro; -macro respondWithMove(commitment, signer) +macro respondWithMove(commitment) begin if /\ challengeOngoing - /\ validTransition(commitment, signer) + /\ validTransition(commitment) then clearChallenge(commitment.turnNumber); +else + print(<>); + assert FALSE; end if; end macro; -macro respondWithAlternativeMove(commitment, signer) +macro respondWithAlternativeMove(commitment) \* turnNumber is the turn number of the last state in the round. begin if @@ -138,10 +141,9 @@ while AliceCanTakeAction do if channel.mode = ChannelMode.CHALLENGE then if - /\ AlicesMove(channel.challenge.turnNumber) + /\ AlicesMove(channel.challenge.turnNumber - 1) /\ channel.challenge.turnNumber >= StartingTurnNumber - then Respond: respondWithMove([ turnNumber |-> channel.turnNumber + 1 ], Alice); - elsif FALSE then skip; + then Respond: respondWithMove([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]); elsif /\ channel.turnNumber < StartingTurnNumber then @@ -149,14 +151,11 @@ do \* She can therefore call refute with exactly one commitment, according to \* the channel's current turnNumber. Refute: refute(CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.challenge.signer % NumParticipants); - end if; - FinalizeChannel: - \* If the challenge wasn't cleared, then Alice's strategy has failed, finalizing the channel. - if channel.mode = ChannelMode.CHALLENGE then - channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.challenge.turnNumber - 1 ]; + else + \* If the challenge wasn't cleared, then Alice's strategy has failed, finalizing the channel. + Finalize: channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.challenge.turnNumber - 1 ]; end if; elsif challenge = NULL then - ForceMove: forceMove([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ]); end if; end while; @@ -179,16 +178,16 @@ begin (***************************************************************************) EveMoves: while AliceCanTakeAction do - either +\* either ForceMove: with n \in NumParticipants..StartingTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } do forceMove([ turnNumber |-> n, signer |-> idx ]); end with; - or RespondWithMove: skip; - or RespondWithAlternativeMove: skip; - or Refute: skip - or Sleep: skip; - end either; +\* or RespondWithMove: skip; +\* or RespondWithAlternativeMove: skip; +\* or Refute: skip +\* or Sleep: skip; +\* end either; end while; end process; @@ -197,8 +196,6 @@ end algorithm; \* BEGIN TRANSLATION -\* Label Refute of process alice at line 91 col 1 changed to Refute_ -\* Label ForceMove of process alice at line 100 col 1 changed to ForceMove_ VARIABLES channel, challenge, pc (* define statement *) @@ -210,9 +207,9 @@ challengerSigIsValid(turnNumber, challenger) == ELSE challenger = Eve progressesChannel(turnNumber) == turnNumber > channel.turnNumber validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] -validTransition(c, s) == - /\ c.turnNumber = channel.turnNumber + 1 - /\ IF AlicesMove(channel.turnNumber) THEN s = Alice ELSE s = Eve +validTransition(commitment) == + /\ commitment.turnNumber = channel.challenge.turnNumber + 1 + /\ commitment.turnNumber % NumParticipants = commitment.signer % NumParticipants AliceCanTakeAction == \/ /\ AlicesMove(channel.turnNumber) @@ -250,71 +247,62 @@ adjudicator == Adjudicator \/ HandleChallenge AliceMoves == /\ pc[Alice] = "AliceMoves" /\ IF AliceCanTakeAction THEN /\ IF channel.mode = ChannelMode.CHALLENGE - THEN /\ IF /\ AlicesMove(channel.challenge.turnNumber) + THEN /\ IF /\ AlicesMove(channel.challenge.turnNumber - 1) /\ channel.challenge.turnNumber >= StartingTurnNumber THEN /\ pc' = [pc EXCEPT ![Alice] = "Respond"] - ELSE /\ IF FALSE - THEN /\ TRUE - /\ pc' = [pc EXCEPT ![Alice] = "FinalizeChannel"] - ELSE /\ IF /\ channel.turnNumber < StartingTurnNumber - THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute_"] - ELSE /\ pc' = [pc EXCEPT ![Alice] = "FinalizeChannel"] + ELSE /\ IF /\ channel.turnNumber < StartingTurnNumber + THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute"] + ELSE /\ pc' = [pc EXCEPT ![Alice] = "Finalize"] + /\ UNCHANGED challenge ELSE /\ IF challenge = NULL - THEN /\ pc' = [pc EXCEPT ![Alice] = "ForceMove_"] - ELSE /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + THEN /\ Assert(validCommitment(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ])), + "Failure of assertion at line 103, column 1 of macro called at line 159, column 9.") + /\ IF /\ channelOpen + /\ progressesChannel(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ]).turnNumber) + THEN /\ challenge' = [ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ] + ELSE /\ TRUE + /\ UNCHANGED challenge + ELSE /\ TRUE + /\ UNCHANGED challenge + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] - /\ UNCHANGED << channel, challenge >> - -FinalizeChannel == /\ pc[Alice] = "FinalizeChannel" - /\ IF channel.mode = ChannelMode.CHALLENGE - THEN /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.challenge.turnNumber - 1 ] - ELSE /\ TRUE - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED challenge + /\ UNCHANGED challenge + /\ UNCHANGED channel Respond == /\ pc[Alice] = "Respond" /\ IF /\ challengeOngoing - /\ validTransition(([ turnNumber |-> channel.turnNumber + 1 ]), Alice) - THEN /\ Assert((([ turnNumber |-> channel.turnNumber + 1 ]).turnNumber) \in Nat, - "Failure of assertion at line 60, column 1 of macro called at line 143, column 23.") - /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (([ turnNumber |-> channel.turnNumber + 1 ]).turnNumber) ] - ELSE /\ TRUE + /\ validTransition(([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ])) + THEN /\ Assert((([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]).turnNumber) \in Nat, + "Failure of assertion at line 60, column 1 of macro called at line 146, column 23.") + /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]).turnNumber) ] + ELSE /\ PrintT((< channel.challenge.turnNumber, signer |-> AlicesIDX ]), validTransition(([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]))>>)) + /\ Assert(FALSE, + "Failure of assertion at line 78, column 5 of macro called at line 146, column 23.") /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![Alice] = "FinalizeChannel"] + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED challenge -Refute_ == /\ pc[Alice] = "Refute_" - /\ IF /\ challengeOngoing - /\ (CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.challenge.signer % NumParticipants) > channel.turnNumber - THEN /\ Assert((channel.turnNumber) \in Nat, - "Failure of assertion at line 60, column 1 of macro called at line 151, column 21.") - /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (channel.turnNumber) ] - ELSE /\ TRUE - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![Alice] = "FinalizeChannel"] - /\ UNCHANGED challenge +Refute == /\ pc[Alice] = "Refute" + /\ IF /\ challengeOngoing + /\ (CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.challenge.signer % NumParticipants) > channel.turnNumber + THEN /\ Assert((channel.turnNumber) \in Nat, + "Failure of assertion at line 60, column 1 of macro called at line 153, column 21.") + /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (channel.turnNumber) ] + ELSE /\ TRUE + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + /\ UNCHANGED challenge -ForceMove_ == /\ pc[Alice] = "ForceMove_" - /\ Assert(validCommitment(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ])), - "Failure of assertion at line 100, column 1 of macro called at line 160, column 9.") - /\ IF /\ channelOpen - /\ progressesChannel(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ]).turnNumber) - THEN /\ challenge' = [ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ] - ELSE /\ TRUE - /\ UNCHANGED challenge - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED channel +Finalize == /\ pc[Alice] = "Finalize" + /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.challenge.turnNumber - 1 ] + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + /\ UNCHANGED challenge -alice == AliceMoves \/ FinalizeChannel \/ Respond \/ Refute_ \/ ForceMove_ +alice == AliceMoves \/ Respond \/ Refute \/ Finalize EveMoves == /\ pc[Eve] = "EveMoves" /\ IF AliceCanTakeAction - THEN /\ \/ /\ pc' = [pc EXCEPT ![Eve] = "ForceMove"] - \/ /\ pc' = [pc EXCEPT ![Eve] = "RespondWithMove"] - \/ /\ pc' = [pc EXCEPT ![Eve] = "RespondWithAlternativeMove"] - \/ /\ pc' = [pc EXCEPT ![Eve] = "Refute"] - \/ /\ pc' = [pc EXCEPT ![Eve] = "Sleep"] + THEN /\ pc' = [pc EXCEPT ![Eve] = "ForceMove"] ELSE /\ pc' = [pc EXCEPT ![Eve] = "Done"] /\ UNCHANGED << channel, challenge >> @@ -322,7 +310,7 @@ ForceMove == /\ pc[Eve] = "ForceMove" /\ \E n \in NumParticipants..StartingTurnNumber: \E idx \in ParticipantIDXs \ { AlicesIDX }: /\ Assert(validCommitment(([ turnNumber |-> n, signer |-> idx ])), - "Failure of assertion at line 100, column 1 of macro called at line 185, column 13.") + "Failure of assertion at line 103, column 1 of macro called at line 184, column 13.") /\ IF /\ channelOpen /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ]).turnNumber) THEN /\ challenge' = [ turnNumber |-> n, signer |-> idx ] @@ -331,28 +319,7 @@ ForceMove == /\ pc[Eve] = "ForceMove" /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] /\ UNCHANGED channel -RespondWithMove == /\ pc[Eve] = "RespondWithMove" - /\ TRUE - /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] - /\ UNCHANGED << channel, challenge >> - -RespondWithAlternativeMove == /\ pc[Eve] = "RespondWithAlternativeMove" - /\ TRUE - /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] - /\ UNCHANGED << channel, challenge >> - -Refute == /\ pc[Eve] = "Refute" - /\ TRUE - /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] - /\ UNCHANGED << channel, challenge >> - -Sleep == /\ pc[Eve] = "Sleep" - /\ TRUE - /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] - /\ UNCHANGED << channel, challenge >> - -eve == EveMoves \/ ForceMove \/ RespondWithMove - \/ RespondWithAlternativeMove \/ Refute \/ Sleep +eve == EveMoves \/ ForceMove (* Allow infinite stuttering to prevent deadlock on termination. *) Terminating == /\ \A self \in ProcSet: pc[self] = "Done" @@ -399,5 +366,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Wed Aug 28 13:55:59 MDT 2019 by andrewstewart +\* Last modified Wed Aug 28 14:18:54 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 854d5e535b4a93758ca8ba3ce1b3a071236a71ea Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Wed, 28 Aug 2019 14:22:38 -0600 Subject: [PATCH 25/66] Minimal spec exhibiting force-move protocol issue At this point, by front-running, Eve can force an infinite loop of forceMoves, where Alice has no choice but to call refute. Since refute does not increment the channel's turnNumber on chain, this creates an infinite loop. --- ForceMove/ForceMove.tla | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index c8fe782..6b7c096 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -80,7 +80,6 @@ end if; end macro; macro respondWithAlternativeMove(commitment) -\* turnNumber is the turn number of the last state in the round. begin if /\ challengeOngoing @@ -178,16 +177,10 @@ begin (***************************************************************************) EveMoves: while AliceCanTakeAction do -\* either - ForceMove: - with n \in NumParticipants..StartingTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } do - forceMove([ turnNumber |-> n, signer |-> idx ]); - end with; -\* or RespondWithMove: skip; -\* or RespondWithAlternativeMove: skip; -\* or Refute: skip -\* or Sleep: skip; -\* end either; + ForceMove: + with n \in NumParticipants..StartingTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } do + forceMove([ turnNumber |-> n, signer |-> idx ]); + end with; end while; end process; @@ -310,7 +303,7 @@ ForceMove == /\ pc[Eve] = "ForceMove" /\ \E n \in NumParticipants..StartingTurnNumber: \E idx \in ParticipantIDXs \ { AlicesIDX }: /\ Assert(validCommitment(([ turnNumber |-> n, signer |-> idx ])), - "Failure of assertion at line 103, column 1 of macro called at line 184, column 13.") + "Failure of assertion at line 103, column 1 of macro called at line 183, column 9.") /\ IF /\ channelOpen /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ]).turnNumber) THEN /\ challenge' = [ turnNumber |-> n, signer |-> idx ] @@ -366,5 +359,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Wed Aug 28 14:18:54 MDT 2019 by andrewstewart +\* Last modified Wed Aug 28 14:20:50 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 36a05673826213d9028bcab4cfd13d7cf086c88a Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Thu, 29 Aug 2019 15:34:22 -0700 Subject: [PATCH 26/66] Always store a challenge --- ForceMove/ForceMove.tla | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 6b7c096..2bc67cd 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -32,7 +32,7 @@ ASSUME (* --algorithm forceMove variables - channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN ], + channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN, challenge |-> NULL ], challenge = NULL define @@ -58,7 +58,7 @@ end define; macro clearChallenge(turnNumber) begin assert turnNumber \in Nat; -channel := [ mode |-> ChannelMode.OPEN, turnNumber |-> turnNumber ]; +channel := [ mode |-> ChannelMode.OPEN, turnNumber |-> turnNumber, challenge |-> NULL ]; end macro; macro setChallenge(commitment) @@ -215,7 +215,7 @@ vars == << channel, challenge, pc >> ProcSet == {"Adjudicator"} \cup {Alice} \cup {Eve} Init == (* Global variables *) - /\ channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN ] + /\ channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN, challenge |-> NULL ] /\ challenge = NULL /\ pc = [self \in ProcSet |-> CASE self = "Adjudicator" -> "Adjudicator" [] self = Alice -> "AliceMoves" @@ -249,7 +249,7 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" /\ UNCHANGED challenge ELSE /\ IF challenge = NULL THEN /\ Assert(validCommitment(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ])), - "Failure of assertion at line 103, column 1 of macro called at line 159, column 9.") + "Failure of assertion at line 102, column 1 of macro called at line 158, column 9.") /\ IF /\ channelOpen /\ progressesChannel(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ]).turnNumber) THEN /\ challenge' = [ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ] @@ -266,11 +266,11 @@ Respond == /\ pc[Alice] = "Respond" /\ IF /\ challengeOngoing /\ validTransition(([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ])) THEN /\ Assert((([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]).turnNumber) \in Nat, - "Failure of assertion at line 60, column 1 of macro called at line 146, column 23.") - /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]).turnNumber) ] + "Failure of assertion at line 60, column 1 of macro called at line 145, column 23.") + /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]).turnNumber), challenge |-> NULL ] ELSE /\ PrintT((< channel.challenge.turnNumber, signer |-> AlicesIDX ]), validTransition(([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]))>>)) /\ Assert(FALSE, - "Failure of assertion at line 78, column 5 of macro called at line 146, column 23.") + "Failure of assertion at line 78, column 5 of macro called at line 145, column 23.") /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED challenge @@ -279,8 +279,8 @@ Refute == /\ pc[Alice] = "Refute" /\ IF /\ challengeOngoing /\ (CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.challenge.signer % NumParticipants) > channel.turnNumber THEN /\ Assert((channel.turnNumber) \in Nat, - "Failure of assertion at line 60, column 1 of macro called at line 153, column 21.") - /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (channel.turnNumber) ] + "Failure of assertion at line 60, column 1 of macro called at line 152, column 21.") + /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (channel.turnNumber), challenge |-> NULL ] ELSE /\ TRUE /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] @@ -303,7 +303,7 @@ ForceMove == /\ pc[Eve] = "ForceMove" /\ \E n \in NumParticipants..StartingTurnNumber: \E idx \in ParticipantIDXs \ { AlicesIDX }: /\ Assert(validCommitment(([ turnNumber |-> n, signer |-> idx ])), - "Failure of assertion at line 103, column 1 of macro called at line 183, column 9.") + "Failure of assertion at line 102, column 1 of macro called at line 182, column 9.") /\ IF /\ channelOpen /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ]).turnNumber) THEN /\ challenge' = [ turnNumber |-> n, signer |-> idx ] @@ -331,16 +331,14 @@ Termination == <>(\A self \in ProcSet: pc[self] = "Done") \* END TRANSLATION AllowedTurnNumbers == 0..(StartingTurnNumber + NumParticipants) -AllowedChallenges == [ turnNumber: AllowedTurnNumbers, signer: ParticipantIDXs ] -AllowedChannels == {} - \cup [ turnNumber: AllowedTurnNumbers, mode: { ChannelMode.OPEN, ChannelMode.FINALIZED } ] - \cup [ turnNumber: AllowedTurnNumbers, mode: { ChannelMode.CHALLENGE }, challenge: AllowedChallenges ] +AllowedChallenges == [ turnNumber: AllowedTurnNumbers, signer: ParticipantIDXs ] \cup { NULL } +AllowedChannels == [ turnNumber: AllowedTurnNumbers, mode: Range(ChannelMode), challenge: AllowedChallenges ] \* Safety properties TypeOK == - /\ channel \in AllowedChannels - /\ challenge \in { NULL } \cup AllowedChallenges + /\ channel \in AllowedChannels + /\ challenge \in AllowedChallenges \* Liveness properties AliceCanProgressChannel == <>[]( @@ -359,5 +357,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Wed Aug 28 14:20:50 MDT 2019 by andrewstewart +\* Last modified Thu Aug 29 16:34:00 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From cf05bcc4290e5e74049a8fcace8799929eb91f8c Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Thu, 29 Aug 2019 16:05:28 -0700 Subject: [PATCH 27/66] Add EveCanTakeAction --- ForceMove/ForceMove.tla | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 2bc67cd..98d6001 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -52,7 +52,7 @@ AliceCanTakeAction == \/ /\ AlicesMove(channel.turnNumber) /\ channel.turnNumber = LatestTurnNumber \/ channel.mode # ChannelMode.FINALIZED - +EveCanTakeAction == AliceCanTakeAction end define; macro clearChallenge(turnNumber) @@ -114,7 +114,9 @@ begin (* This process records submitted channels. *) (***************************************************************************) Adjudicator: -while AliceCanTakeAction +while + \/ AliceCanTakeAction + \/ EveCanTakeAction do HandleChallenge: if challenge # NULL then channel := [ mode |-> ChannelMode.CHALLENGE, challenge |-> challenge ] @@ channel; @@ -176,7 +178,7 @@ begin (* challenge to expire. *) (***************************************************************************) EveMoves: -while AliceCanTakeAction do +while EveCanTakeAction do ForceMove: with n \in NumParticipants..StartingTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } do forceMove([ turnNumber |-> n, signer |-> idx ]); @@ -208,6 +210,7 @@ AliceCanTakeAction == \/ /\ AlicesMove(channel.turnNumber) /\ channel.turnNumber = LatestTurnNumber \/ channel.mode # ChannelMode.FINALIZED +EveCanTakeAction == AliceCanTakeAction vars == << channel, challenge, pc >> @@ -222,7 +225,8 @@ Init == (* Global variables *) [] self = Eve -> "EveMoves"] Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" - /\ IF AliceCanTakeAction + /\ IF \/ AliceCanTakeAction + \/ EveCanTakeAction THEN /\ pc' = [pc EXCEPT !["Adjudicator"] = "HandleChallenge"] ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "Done"] /\ UNCHANGED << channel, challenge >> @@ -249,7 +253,7 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" /\ UNCHANGED challenge ELSE /\ IF challenge = NULL THEN /\ Assert(validCommitment(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ])), - "Failure of assertion at line 102, column 1 of macro called at line 158, column 9.") + "Failure of assertion at line 102, column 1 of macro called at line 160, column 9.") /\ IF /\ channelOpen /\ progressesChannel(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ]).turnNumber) THEN /\ challenge' = [ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ] @@ -266,11 +270,11 @@ Respond == /\ pc[Alice] = "Respond" /\ IF /\ challengeOngoing /\ validTransition(([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ])) THEN /\ Assert((([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]).turnNumber) \in Nat, - "Failure of assertion at line 60, column 1 of macro called at line 145, column 23.") + "Failure of assertion at line 60, column 1 of macro called at line 147, column 23.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]).turnNumber), challenge |-> NULL ] ELSE /\ PrintT((< channel.challenge.turnNumber, signer |-> AlicesIDX ]), validTransition(([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]))>>)) /\ Assert(FALSE, - "Failure of assertion at line 78, column 5 of macro called at line 145, column 23.") + "Failure of assertion at line 78, column 5 of macro called at line 147, column 23.") /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED challenge @@ -279,7 +283,7 @@ Refute == /\ pc[Alice] = "Refute" /\ IF /\ challengeOngoing /\ (CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.challenge.signer % NumParticipants) > channel.turnNumber THEN /\ Assert((channel.turnNumber) \in Nat, - "Failure of assertion at line 60, column 1 of macro called at line 152, column 21.") + "Failure of assertion at line 60, column 1 of macro called at line 154, column 21.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (channel.turnNumber), challenge |-> NULL ] ELSE /\ TRUE /\ UNCHANGED channel @@ -294,7 +298,7 @@ Finalize == /\ pc[Alice] = "Finalize" alice == AliceMoves \/ Respond \/ Refute \/ Finalize EveMoves == /\ pc[Eve] = "EveMoves" - /\ IF AliceCanTakeAction + /\ IF EveCanTakeAction THEN /\ pc' = [pc EXCEPT ![Eve] = "ForceMove"] ELSE /\ pc' = [pc EXCEPT ![Eve] = "Done"] /\ UNCHANGED << channel, challenge >> @@ -303,7 +307,7 @@ ForceMove == /\ pc[Eve] = "ForceMove" /\ \E n \in NumParticipants..StartingTurnNumber: \E idx \in ParticipantIDXs \ { AlicesIDX }: /\ Assert(validCommitment(([ turnNumber |-> n, signer |-> idx ])), - "Failure of assertion at line 102, column 1 of macro called at line 182, column 9.") + "Failure of assertion at line 102, column 1 of macro called at line 184, column 9.") /\ IF /\ channelOpen /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ]).turnNumber) THEN /\ challenge' = [ turnNumber |-> n, signer |-> idx ] @@ -357,5 +361,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Thu Aug 29 16:34:00 MDT 2019 by andrewstewart +\* Last modified Thu Aug 29 17:05:18 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 89143ebf0f8e6df33d2e8b6a5efbd7453e0e89b5 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Fri, 30 Aug 2019 09:47:23 -0700 Subject: [PATCH 28/66] Channel has one turn number per participant --- ForceMove/ForceMove.tla | 61 +++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 98d6001..45709a5 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -22,6 +22,7 @@ Names == { Alice, Eve } ParticipantIDXs == 1..NumParticipants AlicesCommitments == StartingTurnNumber..LatestTurnNumber AlicesMove(turnNumber) == (turnNumber + 1) % NumParticipants = AlicesIDX % NumParticipants +ParticipantIDX(turnNumber) == 1 + ((turnNumber - 1) % NumParticipants) ASSUME /\ StartingTurnNumber \in Nat @@ -32,7 +33,7 @@ ASSUME (* --algorithm forceMove variables - channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN, challenge |-> NULL ], + channel = [turnNumber |-> [p \in ParticipantIDXs |-> 0], mode |-> ChannelMode.OPEN, challenge |-> NULL ], challenge = NULL define @@ -42,15 +43,15 @@ challengerSigIsValid(turnNumber, challenger) == IF AlicesMove(turnNumber) THEN challenge = Alice ELSE challenger = Eve -progressesChannel(turnNumber) == turnNumber > channel.turnNumber +progressesChannel(commitment) == commitment.turnNumber > channel.turnNumber[commitment.signer] validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(commitment) == /\ commitment.turnNumber = channel.challenge.turnNumber + 1 /\ commitment.turnNumber % NumParticipants = commitment.signer % NumParticipants -AliceCanTakeAction == - \/ /\ AlicesMove(channel.turnNumber) - /\ channel.turnNumber = LatestTurnNumber +AliceCanTakeAction == LET turnNumber == channel.turnNumber[AlicesIDX] IN + \/ /\ AlicesMove(turnNumber) + /\ turnNumber = LatestTurnNumber \/ channel.mode # ChannelMode.FINALIZED EveCanTakeAction == AliceCanTakeAction end define; @@ -61,6 +62,7 @@ assert turnNumber \in Nat; channel := [ mode |-> ChannelMode.OPEN, turnNumber |-> turnNumber, challenge |-> NULL ]; end macro; + macro setChallenge(commitment) begin \*assert validCommitment(commitment); @@ -83,7 +85,7 @@ macro respondWithAlternativeMove(commitment) begin if /\ challengeOngoing - /\ commitment.turnNumber > channel.turnNumber + /\ commitment.turnNumber > channel.challenge.turnNumber + 1 then clearChallenge(commitment.turnNumber); end if; end macro; @@ -92,8 +94,9 @@ macro refute(turnNumber) begin if /\ challengeOngoing - /\ turnNumber > channel.turnNumber -then clearChallenge(channel.turnNumber); + /\ turnNumber > channel.turnNumber[ParticipantIDX(turnNumber)] +then channel := [ mode |-> ChannelMode.OPEN, challenge |-> NULL ] @@ channel; + end if; end macro; @@ -102,7 +105,7 @@ begin assert validCommitment(commitment); if /\ channelOpen - /\ progressesChannel(commitment.turnNumber) + /\ progressesChannel(commitment) then setChallenge(commitment) end if; @@ -146,7 +149,7 @@ do /\ channel.challenge.turnNumber >= StartingTurnNumber then Respond: respondWithMove([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]); elsif - /\ channel.turnNumber < StartingTurnNumber + /\ channel.turnNumber[AlicesIDX] < StartingTurnNumber then \* Alice has signed commitments from StartingTurnNumber up to LastTurnNumber. \* She can therefore call refute with exactly one commitment, according to @@ -200,15 +203,15 @@ challengerSigIsValid(turnNumber, challenger) == IF AlicesMove(turnNumber) THEN challenge = Alice ELSE challenger = Eve -progressesChannel(turnNumber) == turnNumber > channel.turnNumber +progressesChannel(commitment) == commitment.turnNumber > channel.turnNumber[commitment.signer] validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(commitment) == /\ commitment.turnNumber = channel.challenge.turnNumber + 1 /\ commitment.turnNumber % NumParticipants = commitment.signer % NumParticipants -AliceCanTakeAction == - \/ /\ AlicesMove(channel.turnNumber) - /\ channel.turnNumber = LatestTurnNumber +AliceCanTakeAction == LET turnNumber == channel.turnNumber[AlicesIDX] IN + \/ /\ AlicesMove(turnNumber) + /\ turnNumber = LatestTurnNumber \/ channel.mode # ChannelMode.FINALIZED EveCanTakeAction == AliceCanTakeAction @@ -218,7 +221,7 @@ vars == << channel, challenge, pc >> ProcSet == {"Adjudicator"} \cup {Alice} \cup {Eve} Init == (* Global variables *) - /\ channel = [turnNumber |-> 0, mode |-> ChannelMode.OPEN, challenge |-> NULL ] + /\ channel = [turnNumber |-> [p \in ParticipantIDXs |-> 0], mode |-> ChannelMode.OPEN, challenge |-> NULL ] /\ challenge = NULL /\ pc = [self \in ProcSet |-> CASE self = "Adjudicator" -> "Adjudicator" [] self = Alice -> "AliceMoves" @@ -247,15 +250,15 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" THEN /\ IF /\ AlicesMove(channel.challenge.turnNumber - 1) /\ channel.challenge.turnNumber >= StartingTurnNumber THEN /\ pc' = [pc EXCEPT ![Alice] = "Respond"] - ELSE /\ IF /\ channel.turnNumber < StartingTurnNumber + ELSE /\ IF /\ channel.turnNumber[AlicesIDX] < StartingTurnNumber THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute"] ELSE /\ pc' = [pc EXCEPT ![Alice] = "Finalize"] /\ UNCHANGED challenge ELSE /\ IF challenge = NULL THEN /\ Assert(validCommitment(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ])), - "Failure of assertion at line 102, column 1 of macro called at line 160, column 9.") + "Failure of assertion at line 105, column 1 of macro called at line 163, column 9.") /\ IF /\ channelOpen - /\ progressesChannel(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ]).turnNumber) + /\ progressesChannel(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ])) THEN /\ challenge' = [ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ] ELSE /\ TRUE /\ UNCHANGED challenge @@ -270,21 +273,19 @@ Respond == /\ pc[Alice] = "Respond" /\ IF /\ challengeOngoing /\ validTransition(([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ])) THEN /\ Assert((([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]).turnNumber) \in Nat, - "Failure of assertion at line 60, column 1 of macro called at line 147, column 23.") + "Failure of assertion at line 61, column 1 of macro called at line 150, column 23.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]).turnNumber), challenge |-> NULL ] ELSE /\ PrintT((< channel.challenge.turnNumber, signer |-> AlicesIDX ]), validTransition(([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]))>>)) /\ Assert(FALSE, - "Failure of assertion at line 78, column 5 of macro called at line 147, column 23.") + "Failure of assertion at line 80, column 5 of macro called at line 150, column 23.") /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED challenge Refute == /\ pc[Alice] = "Refute" /\ IF /\ challengeOngoing - /\ (CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.challenge.signer % NumParticipants) > channel.turnNumber - THEN /\ Assert((channel.turnNumber) \in Nat, - "Failure of assertion at line 60, column 1 of macro called at line 154, column 21.") - /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (channel.turnNumber), challenge |-> NULL ] + /\ (CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.challenge.signer % NumParticipants) > channel.turnNumber[ParticipantIDX((CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.challenge.signer % NumParticipants))] + THEN /\ channel' = [ mode |-> ChannelMode.OPEN, challenge |-> NULL ] @@ channel ELSE /\ TRUE /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] @@ -307,9 +308,9 @@ ForceMove == /\ pc[Eve] = "ForceMove" /\ \E n \in NumParticipants..StartingTurnNumber: \E idx \in ParticipantIDXs \ { AlicesIDX }: /\ Assert(validCommitment(([ turnNumber |-> n, signer |-> idx ])), - "Failure of assertion at line 102, column 1 of macro called at line 184, column 9.") + "Failure of assertion at line 105, column 1 of macro called at line 187, column 9.") /\ IF /\ channelOpen - /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ]).turnNumber) + /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ])) THEN /\ challenge' = [ turnNumber |-> n, signer |-> idx ] ELSE /\ TRUE /\ UNCHANGED challenge @@ -336,7 +337,7 @@ Termination == <>(\A self \in ProcSet: pc[self] = "Done") AllowedTurnNumbers == 0..(StartingTurnNumber + NumParticipants) AllowedChallenges == [ turnNumber: AllowedTurnNumbers, signer: ParticipantIDXs ] \cup { NULL } -AllowedChannels == [ turnNumber: AllowedTurnNumbers, mode: Range(ChannelMode), challenge: AllowedChallenges ] +AllowedChannels == [ turnNumber: { [p \in ParticipantIDXs |-> n] : n \in 0..LatestTurnNumber+NumParticipants }, mode: Range(ChannelMode), challenge: AllowedChallenges ] \* Safety properties @@ -347,12 +348,12 @@ TypeOK == \* Liveness properties AliceCanProgressChannel == <>[]( /\ channel.mode = ChannelMode.OPEN - /\ channel.turnNumber = AlicesGoalTurnNumber + /\ channel.turnNumber[AlicesIDX] = AlicesGoalTurnNumber ) FinalizedWithLatestTurnNumber == <>[]( /\ channel.mode = ChannelMode.FINALIZED - /\ channel.turnNumber = LatestTurnNumber + /\ channel.turnNumber[AlicesIDX] = LatestTurnNumber ) AliceDoesNotLoseFunds == @@ -361,5 +362,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Thu Aug 29 17:05:18 MDT 2019 by andrewstewart +\* Last modified Fri Aug 30 10:46:51 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 6469cf462a8f9bc2a01d7b69ab405ac4c6284974 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 3 Sep 2019 11:51:44 -0600 Subject: [PATCH 29/66] Update some definitions At this point, if Alice has commitments {5,6} and Eve calls ForceMove(5), then Alice can't refute, and instead needs to respond with a move. --- ForceMove/ForceMove.tla | 87 +++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 47 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 45709a5..8d6bfde 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -21,14 +21,14 @@ AlicesGoalTurnNumber == LatestTurnNumber + 1 Names == { Alice, Eve } ParticipantIDXs == 1..NumParticipants AlicesCommitments == StartingTurnNumber..LatestTurnNumber -AlicesMove(turnNumber) == (turnNumber + 1) % NumParticipants = AlicesIDX % NumParticipants ParticipantIDX(turnNumber) == 1 + ((turnNumber - 1) % NumParticipants) +AlicesMove(turnNumber) == ParticipantIDX(turnNumber) = AlicesIDX ASSUME /\ StartingTurnNumber \in Nat /\ NumParticipants \in Nat \ { 1 } /\ AlicesIDX \in ParticipantIDXs - /\ ~AlicesMove(LatestTurnNumber) + /\ ~AlicesMove(LatestTurnNumber + 1) (* --algorithm forceMove @@ -49,11 +49,12 @@ validTransition(commitment) == /\ commitment.turnNumber = channel.challenge.turnNumber + 1 /\ commitment.turnNumber % NumParticipants = commitment.signer % NumParticipants -AliceCanTakeAction == LET turnNumber == channel.turnNumber[AlicesIDX] IN - \/ /\ AlicesMove(turnNumber) - /\ turnNumber = LatestTurnNumber - \/ channel.mode # ChannelMode.FINALIZED +AliceCanTakeAction == channel.mode # ChannelMode.FINALIZED EveCanTakeAction == AliceCanTakeAction + +Refutable(n) == TRUE + /\ n % NumParticipants = channel.challenge.signer % NumParticipants + /\ n > channel.challenge.turnNumber end define; macro clearChallenge(turnNumber) @@ -76,7 +77,6 @@ if /\ validTransition(commitment) then clearChallenge(commitment.turnNumber); else - print(<>); assert FALSE; end if; end macro; @@ -95,8 +95,12 @@ begin if /\ challengeOngoing /\ turnNumber > channel.turnNumber[ParticipantIDX(turnNumber)] -then channel := [ mode |-> ChannelMode.OPEN, challenge |-> NULL ] @@ channel; - +then +channel := [ + mode |-> ChannelMode.OPEN, + challenge |-> NULL, + turnNumber |-> [i \in {ParticipantIDX(turnNumber)} |-> turnNumber] @@ channel.turnNumber +]; end if; end macro; @@ -145,19 +149,19 @@ while AliceCanTakeAction do if channel.mode = ChannelMode.CHALLENGE then if - /\ AlicesMove(channel.challenge.turnNumber - 1) - /\ channel.challenge.turnNumber >= StartingTurnNumber - then Respond: respondWithMove([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]); - elsif - /\ channel.turnNumber[AlicesIDX] < StartingTurnNumber + /\ channel.challenge.turnNumber < StartingTurnNumber then \* Alice has signed commitments from StartingTurnNumber up to LastTurnNumber. \* She can therefore call refute with exactly one commitment, according to \* the channel's current turnNumber. - Refute: refute(CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.challenge.signer % NumParticipants); + Refute: + refute( + CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer + ); else \* If the challenge wasn't cleared, then Alice's strategy has failed, finalizing the channel. - Finalize: channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.challenge.turnNumber - 1 ]; + Finalize: + channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber - 1] ] @@ channel; end if; elsif challenge = NULL then forceMove([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ]); @@ -209,12 +213,13 @@ validTransition(commitment) == /\ commitment.turnNumber = channel.challenge.turnNumber + 1 /\ commitment.turnNumber % NumParticipants = commitment.signer % NumParticipants -AliceCanTakeAction == LET turnNumber == channel.turnNumber[AlicesIDX] IN - \/ /\ AlicesMove(turnNumber) - /\ turnNumber = LatestTurnNumber - \/ channel.mode # ChannelMode.FINALIZED +AliceCanTakeAction == channel.mode # ChannelMode.FINALIZED EveCanTakeAction == AliceCanTakeAction +Refutable(n) == TRUE + /\ n % NumParticipants = channel.challenge.signer % NumParticipants + /\ n > channel.challenge.turnNumber + vars == << channel, challenge, pc >> @@ -247,16 +252,13 @@ adjudicator == Adjudicator \/ HandleChallenge AliceMoves == /\ pc[Alice] = "AliceMoves" /\ IF AliceCanTakeAction THEN /\ IF channel.mode = ChannelMode.CHALLENGE - THEN /\ IF /\ AlicesMove(channel.challenge.turnNumber - 1) - /\ channel.challenge.turnNumber >= StartingTurnNumber - THEN /\ pc' = [pc EXCEPT ![Alice] = "Respond"] - ELSE /\ IF /\ channel.turnNumber[AlicesIDX] < StartingTurnNumber - THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute"] - ELSE /\ pc' = [pc EXCEPT ![Alice] = "Finalize"] + THEN /\ IF /\ channel.challenge.turnNumber < StartingTurnNumber + THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute"] + ELSE /\ pc' = [pc EXCEPT ![Alice] = "Finalize"] /\ UNCHANGED challenge ELSE /\ IF challenge = NULL THEN /\ Assert(validCommitment(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ])), - "Failure of assertion at line 105, column 1 of macro called at line 163, column 9.") + "Failure of assertion at line 109, column 1 of macro called at line 167, column 9.") /\ IF /\ channelOpen /\ progressesChannel(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ])) THEN /\ challenge' = [ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ] @@ -269,34 +271,25 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" /\ UNCHANGED challenge /\ UNCHANGED channel -Respond == /\ pc[Alice] = "Respond" - /\ IF /\ challengeOngoing - /\ validTransition(([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ])) - THEN /\ Assert((([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]).turnNumber) \in Nat, - "Failure of assertion at line 61, column 1 of macro called at line 150, column 23.") - /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> (([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]).turnNumber), challenge |-> NULL ] - ELSE /\ PrintT((< channel.challenge.turnNumber, signer |-> AlicesIDX ]), validTransition(([ turnNumber |-> channel.challenge.turnNumber, signer |-> AlicesIDX ]))>>)) - /\ Assert(FALSE, - "Failure of assertion at line 80, column 5 of macro called at line 150, column 23.") - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED challenge - Refute == /\ pc[Alice] = "Refute" /\ IF /\ challengeOngoing - /\ (CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.challenge.signer % NumParticipants) > channel.turnNumber[ParticipantIDX((CHOOSE n \in AlicesCommitments : n % NumParticipants = channel.challenge.signer % NumParticipants))] - THEN /\ channel' = [ mode |-> ChannelMode.OPEN, challenge |-> NULL ] @@ channel + /\ (CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer) > channel.turnNumber[ParticipantIDX((CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer))] + THEN /\ channel' = [ + mode |-> ChannelMode.OPEN, + challenge |-> NULL, + turnNumber |-> [i \in {ParticipantIDX((CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer))} |-> (CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer)] @@ channel.turnNumber + ] ELSE /\ TRUE /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED challenge Finalize == /\ pc[Alice] = "Finalize" - /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> channel.challenge.turnNumber - 1 ] + /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber - 1] ] @@ channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED challenge -alice == AliceMoves \/ Respond \/ Refute \/ Finalize +alice == AliceMoves \/ Refute \/ Finalize EveMoves == /\ pc[Eve] = "EveMoves" /\ IF EveCanTakeAction @@ -308,7 +301,7 @@ ForceMove == /\ pc[Eve] = "ForceMove" /\ \E n \in NumParticipants..StartingTurnNumber: \E idx \in ParticipantIDXs \ { AlicesIDX }: /\ Assert(validCommitment(([ turnNumber |-> n, signer |-> idx ])), - "Failure of assertion at line 105, column 1 of macro called at line 187, column 9.") + "Failure of assertion at line 109, column 1 of macro called at line 191, column 9.") /\ IF /\ channelOpen /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ])) THEN /\ challenge' = [ turnNumber |-> n, signer |-> idx ] @@ -337,7 +330,7 @@ Termination == <>(\A self \in ProcSet: pc[self] = "Done") AllowedTurnNumbers == 0..(StartingTurnNumber + NumParticipants) AllowedChallenges == [ turnNumber: AllowedTurnNumbers, signer: ParticipantIDXs ] \cup { NULL } -AllowedChannels == [ turnNumber: { [p \in ParticipantIDXs |-> n] : n \in 0..LatestTurnNumber+NumParticipants }, mode: Range(ChannelMode), challenge: AllowedChallenges ] +AllowedChannels == [ turnNumber: [ParticipantIDXs -> Nat] , mode: Range(ChannelMode), challenge: AllowedChallenges ] \* Safety properties @@ -362,5 +355,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Fri Aug 30 10:46:51 MDT 2019 by andrewstewart +\* Last modified Tue Sep 03 10:51:23 PDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 79bab9cd6a392daf1a6f9dc5fba5dea6e8d9cbfd Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 3 Sep 2019 13:31:43 -0600 Subject: [PATCH 30/66] Alice can defend against arbitrary forceMoves --- ForceMove/ForceMove.tla | 59 ++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 8d6bfde..dc760a1 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -24,6 +24,8 @@ AlicesCommitments == StartingTurnNumber..LatestTurnNumber ParticipantIDX(turnNumber) == 1 + ((turnNumber - 1) % NumParticipants) AlicesMove(turnNumber) == ParticipantIDX(turnNumber) = AlicesIDX +Maximum(a,b) == IF a > b THEN a ELSE b + ASSUME /\ StartingTurnNumber \in Nat /\ NumParticipants \in Nat \ { 1 } @@ -43,11 +45,11 @@ challengerSigIsValid(turnNumber, challenger) == IF AlicesMove(turnNumber) THEN challenge = Alice ELSE challenger = Eve -progressesChannel(commitment) == commitment.turnNumber > channel.turnNumber[commitment.signer] +progressesChannel(commitment) == commitment.turnNumber >= channel.turnNumber[commitment.signer] validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(commitment) == /\ commitment.turnNumber = channel.challenge.turnNumber + 1 - /\ commitment.turnNumber % NumParticipants = commitment.signer % NumParticipants + /\ commitment.signer = ParticipantIDX(commitment.turnNumber) AliceCanTakeAction == channel.mode # ChannelMode.FINALIZED EveCanTakeAction == AliceCanTakeAction @@ -60,7 +62,7 @@ end define; macro clearChallenge(turnNumber) begin assert turnNumber \in Nat; -channel := [ mode |-> ChannelMode.OPEN, turnNumber |-> turnNumber, challenge |-> NULL ]; +channel := [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], turnNumber)], challenge |-> NULL ]; end macro; @@ -158,13 +160,19 @@ do refute( CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer ); + elsif + /\ channel.challenge.turnNumber >= StartingTurnNumber + /\ AlicesMove(channel.challenge.turnNumber+1) + then + Respond: + respondWithMove([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]); else \* If the challenge wasn't cleared, then Alice's strategy has failed, finalizing the channel. Finalize: - channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber - 1] ] @@ channel; + channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel; end if; elsif challenge = NULL then - forceMove([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ]); + forceMove([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]); end if; end while; end process; @@ -187,7 +195,7 @@ begin EveMoves: while EveCanTakeAction do ForceMove: - with n \in NumParticipants..StartingTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } do + with n \in NumParticipants..LatestTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } do forceMove([ turnNumber |-> n, signer |-> idx ]); end with; end while; @@ -207,11 +215,11 @@ challengerSigIsValid(turnNumber, challenger) == IF AlicesMove(turnNumber) THEN challenge = Alice ELSE challenger = Eve -progressesChannel(commitment) == commitment.turnNumber > channel.turnNumber[commitment.signer] +progressesChannel(commitment) == commitment.turnNumber >= channel.turnNumber[commitment.signer] validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(commitment) == /\ commitment.turnNumber = channel.challenge.turnNumber + 1 - /\ commitment.turnNumber % NumParticipants = commitment.signer % NumParticipants + /\ commitment.signer = ParticipantIDX(commitment.turnNumber) AliceCanTakeAction == channel.mode # ChannelMode.FINALIZED EveCanTakeAction == AliceCanTakeAction @@ -254,14 +262,17 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" THEN /\ IF channel.mode = ChannelMode.CHALLENGE THEN /\ IF /\ channel.challenge.turnNumber < StartingTurnNumber THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute"] - ELSE /\ pc' = [pc EXCEPT ![Alice] = "Finalize"] + ELSE /\ IF /\ channel.challenge.turnNumber >= StartingTurnNumber + /\ AlicesMove(channel.challenge.turnNumber+1) + THEN /\ pc' = [pc EXCEPT ![Alice] = "Respond"] + ELSE /\ pc' = [pc EXCEPT ![Alice] = "Finalize"] /\ UNCHANGED challenge ELSE /\ IF challenge = NULL - THEN /\ Assert(validCommitment(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ])), - "Failure of assertion at line 109, column 1 of macro called at line 167, column 9.") + THEN /\ Assert(validCommitment(([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ])), + "Failure of assertion at line 111, column 1 of macro called at line 175, column 9.") /\ IF /\ channelOpen - /\ progressesChannel(([ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ])) - THEN /\ challenge' = [ turnNumber |-> AlicesGoalTurnNumber, signer |-> AlicesIDX ] + /\ progressesChannel(([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ])) + THEN /\ challenge' = [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ] ELSE /\ TRUE /\ UNCHANGED challenge ELSE /\ TRUE @@ -284,12 +295,24 @@ Refute == /\ pc[Alice] = "Refute" /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED challenge +Respond == /\ pc[Alice] = "Respond" + /\ IF /\ challengeOngoing + /\ validTransition(([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ])) + THEN /\ Assert((([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber) \in Nat, + "Failure of assertion at line 64, column 1 of macro called at line 168, column 17.") + /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber))], challenge |-> NULL ] + ELSE /\ Assert(FALSE, + "Failure of assertion at line 82, column 5 of macro called at line 168, column 17.") + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + /\ UNCHANGED challenge + Finalize == /\ pc[Alice] = "Finalize" - /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber - 1] ] @@ channel + /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED challenge -alice == AliceMoves \/ Refute \/ Finalize +alice == AliceMoves \/ Refute \/ Respond \/ Finalize EveMoves == /\ pc[Eve] = "EveMoves" /\ IF EveCanTakeAction @@ -298,10 +321,10 @@ EveMoves == /\ pc[Eve] = "EveMoves" /\ UNCHANGED << channel, challenge >> ForceMove == /\ pc[Eve] = "ForceMove" - /\ \E n \in NumParticipants..StartingTurnNumber: + /\ \E n \in NumParticipants..LatestTurnNumber: \E idx \in ParticipantIDXs \ { AlicesIDX }: /\ Assert(validCommitment(([ turnNumber |-> n, signer |-> idx ])), - "Failure of assertion at line 109, column 1 of macro called at line 191, column 9.") + "Failure of assertion at line 111, column 1 of macro called at line 199, column 9.") /\ IF /\ channelOpen /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ])) THEN /\ challenge' = [ turnNumber |-> n, signer |-> idx ] @@ -355,5 +378,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Tue Sep 03 10:51:23 PDT 2019 by andrewstewart +\* Last modified Tue Sep 03 12:09:08 PDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From ff673c2406b9b3a44a0c2c95e328a2de2580dba1 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 3 Sep 2019 16:00:06 -0600 Subject: [PATCH 31/66] Add property which is violated if Eve front-runs Alice's challenge --- ForceMove/ForceMove.tla | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index dc760a1..fee4301 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -376,7 +376,13 @@ AliceDoesNotLoseFunds == \/ AliceCanProgressChannel \/ FinalizedWithLatestTurnNumber +\* By checking this property, we can verify Alice's ability to front-run and replace Alice's pending challenge with another challenge. +EveDoesNotFrontRun == [][ + \/ challenge = NULL + \/ challenge' = NULL +]_<> + ============================================================================= \* Modification History -\* Last modified Tue Sep 03 12:09:08 PDT 2019 by andrewstewart +\* Last modified Tue Sep 03 14:59:29 PDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 44f15dcc739c961b54df50bf92e09e2398d2dd14 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Thu, 5 Sep 2019 12:03:40 -0600 Subject: [PATCH 32/66] Rename property in anticipation of other front-runs --- ForceMove/ForceMove.tla | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index fee4301..50f97ae 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -377,12 +377,12 @@ AliceDoesNotLoseFunds == \/ FinalizedWithLatestTurnNumber \* By checking this property, we can verify Alice's ability to front-run and replace Alice's pending challenge with another challenge. -EveDoesNotFrontRun == [][ +EveDoesNotFrontRunChallenges == [][ \/ challenge = NULL \/ challenge' = NULL ]_<> ============================================================================= \* Modification History -\* Last modified Tue Sep 03 14:59:29 PDT 2019 by andrewstewart +\* Last modified Thu Sep 05 10:58:01 PDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 0b09c32765232b94bb5aa08b92ba730dcfafe843 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Fri, 6 Sep 2019 11:27:18 -0600 Subject: [PATCH 33/66] WIP: Eve calls Refute and RespondWithMove --- ForceMove/ForceMove.tla | 105 +++++++++++++++++++++++++++------------- 1 file changed, 71 insertions(+), 34 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 50f97ae..f1303fa 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -149,7 +149,7 @@ begin AliceMoves: while AliceCanTakeAction do - if channel.mode = ChannelMode.CHALLENGE then + if challengeOngoing then if /\ channel.challenge.turnNumber < StartingTurnNumber then @@ -167,7 +167,7 @@ do Respond: respondWithMove([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]); else - \* If the challenge wasn't cleared, then Alice's strategy has failed, finalizing the channel. + \* Alice has run out of allowed actions, resulting in the channel being finalized Finalize: channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel; end if; @@ -194,10 +194,27 @@ begin (***************************************************************************) EveMoves: while EveCanTakeAction do - ForceMove: - with n \in NumParticipants..LatestTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } do - forceMove([ turnNumber |-> n, signer |-> idx ]); - end with; + either ForceMove: + with n \in NumParticipants..LatestTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } do + forceMove([ turnNumber |-> n, signer |-> idx ]); + end with; + or Respond: + if + /\ challengeOngoing + /\ ~AlicesMove(channel.challenge.turnNumber) + then skip; +\* respondWithMove([ +\* turnNumber |-> channel.challenge.turnNumber + 1, +\* signer |-> ParticipantIDX(channel.challenge.turnNumber) +\* ]); + end if; + or Refute: + if + /\ challengeOngoing + /\ ~AlicesMove(channel.challenge.turnNumber) + then skip; + end if; + end either; end while; end process; @@ -206,6 +223,8 @@ end algorithm; \* BEGIN TRANSLATION +\* Label Refute of process alice at line 97 col 1 changed to Refute_ +\* Label Respond of process alice at line 77 col 1 changed to Respond_ VARIABLES channel, challenge, pc (* define statement *) @@ -259,12 +278,12 @@ adjudicator == Adjudicator \/ HandleChallenge AliceMoves == /\ pc[Alice] = "AliceMoves" /\ IF AliceCanTakeAction - THEN /\ IF channel.mode = ChannelMode.CHALLENGE + THEN /\ IF challengeOngoing THEN /\ IF /\ channel.challenge.turnNumber < StartingTurnNumber - THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute"] + THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute_"] ELSE /\ IF /\ channel.challenge.turnNumber >= StartingTurnNumber /\ AlicesMove(channel.challenge.turnNumber+1) - THEN /\ pc' = [pc EXCEPT ![Alice] = "Respond"] + THEN /\ pc' = [pc EXCEPT ![Alice] = "Respond_"] ELSE /\ pc' = [pc EXCEPT ![Alice] = "Finalize"] /\ UNCHANGED challenge ELSE /\ IF challenge = NULL @@ -282,41 +301,43 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" /\ UNCHANGED challenge /\ UNCHANGED channel -Refute == /\ pc[Alice] = "Refute" - /\ IF /\ challengeOngoing - /\ (CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer) > channel.turnNumber[ParticipantIDX((CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer))] - THEN /\ channel' = [ - mode |-> ChannelMode.OPEN, - challenge |-> NULL, - turnNumber |-> [i \in {ParticipantIDX((CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer))} |-> (CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer)] @@ channel.turnNumber - ] - ELSE /\ TRUE - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED challenge - -Respond == /\ pc[Alice] = "Respond" +Refute_ == /\ pc[Alice] = "Refute_" /\ IF /\ challengeOngoing - /\ validTransition(([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ])) - THEN /\ Assert((([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber) \in Nat, - "Failure of assertion at line 64, column 1 of macro called at line 168, column 17.") - /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber))], challenge |-> NULL ] - ELSE /\ Assert(FALSE, - "Failure of assertion at line 82, column 5 of macro called at line 168, column 17.") + /\ (CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer) > channel.turnNumber[ParticipantIDX((CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer))] + THEN /\ channel' = [ + mode |-> ChannelMode.OPEN, + challenge |-> NULL, + turnNumber |-> [i \in {ParticipantIDX((CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer))} |-> (CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer)] @@ channel.turnNumber + ] + ELSE /\ TRUE /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED challenge +Respond_ == /\ pc[Alice] = "Respond_" + /\ IF /\ challengeOngoing + /\ validTransition(([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ])) + THEN /\ Assert((([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber) \in Nat, + "Failure of assertion at line 64, column 1 of macro called at line 168, column 17.") + /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber))], challenge |-> NULL ] + ELSE /\ Assert(FALSE, + "Failure of assertion at line 82, column 5 of macro called at line 168, column 17.") + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + /\ UNCHANGED challenge + Finalize == /\ pc[Alice] = "Finalize" /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED challenge -alice == AliceMoves \/ Refute \/ Respond \/ Finalize +alice == AliceMoves \/ Refute_ \/ Respond_ \/ Finalize EveMoves == /\ pc[Eve] = "EveMoves" /\ IF EveCanTakeAction - THEN /\ pc' = [pc EXCEPT ![Eve] = "ForceMove"] + THEN /\ \/ /\ pc' = [pc EXCEPT ![Eve] = "ForceMove"] + \/ /\ pc' = [pc EXCEPT ![Eve] = "Respond"] + \/ /\ pc' = [pc EXCEPT ![Eve] = "Refute"] ELSE /\ pc' = [pc EXCEPT ![Eve] = "Done"] /\ UNCHANGED << channel, challenge >> @@ -324,7 +345,7 @@ ForceMove == /\ pc[Eve] = "ForceMove" /\ \E n \in NumParticipants..LatestTurnNumber: \E idx \in ParticipantIDXs \ { AlicesIDX }: /\ Assert(validCommitment(([ turnNumber |-> n, signer |-> idx ])), - "Failure of assertion at line 111, column 1 of macro called at line 199, column 9.") + "Failure of assertion at line 111, column 1 of macro called at line 199, column 13.") /\ IF /\ channelOpen /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ])) THEN /\ challenge' = [ turnNumber |-> n, signer |-> idx ] @@ -333,7 +354,23 @@ ForceMove == /\ pc[Eve] = "ForceMove" /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] /\ UNCHANGED channel -eve == EveMoves \/ ForceMove +Respond == /\ pc[Eve] = "Respond" + /\ IF /\ challengeOngoing + /\ ~AlicesMove(channel.challenge.turnNumber) + THEN /\ TRUE + ELSE /\ TRUE + /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] + /\ UNCHANGED << channel, challenge >> + +Refute == /\ pc[Eve] = "Refute" + /\ IF /\ challengeOngoing + /\ ~AlicesMove(channel.challenge.turnNumber) + THEN /\ TRUE + ELSE /\ TRUE + /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] + /\ UNCHANGED << channel, challenge >> + +eve == EveMoves \/ ForceMove \/ Respond \/ Refute (* Allow infinite stuttering to prevent deadlock on termination. *) Terminating == /\ \A self \in ProcSet: pc[self] = "Done" @@ -384,5 +421,5 @@ EveDoesNotFrontRunChallenges == [][ ============================================================================= \* Modification History -\* Last modified Thu Sep 05 10:58:01 PDT 2019 by andrewstewart +\* Last modified Thu Sep 05 18:46:25 PDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 586eea4f4bd935b0191763e710aeab3ca121218b Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Mon, 9 Sep 2019 15:12:56 -0600 Subject: [PATCH 34/66] wip --- ForceMove/ForceMove.tla | 138 +++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 65 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index f1303fa..dbcb145 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -14,6 +14,11 @@ ChannelMode == [ FINALIZED |-> "FINALIZED" ] + +TX_Type == [ + FORCE_MOVE |-> "FORCE_MOVE" +] + Range(f) == { f[x] : x \in DOMAIN f } LatestTurnNumber == StartingTurnNumber + NumParticipants - 1 @@ -21,6 +26,7 @@ AlicesGoalTurnNumber == LatestTurnNumber + 1 Names == { Alice, Eve } ParticipantIDXs == 1..NumParticipants AlicesCommitments == StartingTurnNumber..LatestTurnNumber + ParticipantIDX(turnNumber) == 1 + ((turnNumber - 1) % NumParticipants) AlicesMove(turnNumber) == ParticipantIDX(turnNumber) = AlicesIDX @@ -36,15 +42,11 @@ ASSUME variables channel = [turnNumber |-> [p \in ParticipantIDXs |-> 0], mode |-> ChannelMode.OPEN, challenge |-> NULL ], - challenge = NULL + submittedTX = NULL define challengeOngoing == channel.mode = ChannelMode.CHALLENGE channelOpen == channel.mode = ChannelMode.OPEN -challengerSigIsValid(turnNumber, challenger) == - IF AlicesMove(turnNumber) - THEN challenge = Alice - ELSE challenger = Eve progressesChannel(commitment) == commitment.turnNumber >= channel.turnNumber[commitment.signer] validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(commitment) == @@ -62,14 +64,18 @@ end define; macro clearChallenge(turnNumber) begin assert turnNumber \in Nat; -channel := [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], turnNumber)], challenge |-> NULL ]; +channel := [ + mode |-> ChannelMode.OPEN, + turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], turnNumber)], + challenge |-> NULL +]; end macro; -macro setChallenge(commitment) +macro submitChallenge(commitment) begin -\*assert validCommitment(commitment); -challenge := commitment; +assert submittedTX = NULL; +submittedTX := [ commitment |-> commitment, type |-> TX_Type.FORCE_MOVE ]; end macro; macro respondWithMove(commitment) @@ -112,7 +118,7 @@ assert validCommitment(commitment); if /\ channelOpen /\ progressesChannel(commitment) -then setChallenge(commitment) +then submitChallenge(commitment) end if; end macro; @@ -126,10 +132,10 @@ Adjudicator: while \/ AliceCanTakeAction \/ EveCanTakeAction -do HandleChallenge: - if challenge # NULL then - channel := [ mode |-> ChannelMode.CHALLENGE, challenge |-> challenge ] @@ channel; - challenge := NULL; +do + if submittedTX # NULL then + channel := [ mode |-> ChannelMode.CHALLENGE, challenge |-> submittedTX.commitment ] @@ channel; + submittedTX := NULL; end if; end while; end process; @@ -171,7 +177,7 @@ do Finalize: channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel; end if; - elsif challenge = NULL then + elsif submittedTX # NULL then forceMove([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]); end if; end while; @@ -195,7 +201,9 @@ begin EveMoves: while EveCanTakeAction do either ForceMove: - with n \in NumParticipants..LatestTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } do + with n \in NumParticipants..LatestTurnNumber, + idx \in ParticipantIDXs \ { AlicesIDX } + do forceMove([ turnNumber |-> n, signer |-> idx ]); end with; or Respond: @@ -223,17 +231,13 @@ end algorithm; \* BEGIN TRANSLATION -\* Label Refute of process alice at line 97 col 1 changed to Refute_ -\* Label Respond of process alice at line 77 col 1 changed to Respond_ -VARIABLES channel, challenge, pc +\* Label Refute of process alice at line 103 col 1 changed to Refute_ +\* Label Respond of process alice at line 83 col 1 changed to Respond_ +VARIABLES channel, submittedTX, pc (* define statement *) challengeOngoing == channel.mode = ChannelMode.CHALLENGE channelOpen == channel.mode = ChannelMode.OPEN -challengerSigIsValid(turnNumber, challenger) == - IF AlicesMove(turnNumber) - THEN challenge = Alice - ELSE challenger = Eve progressesChannel(commitment) == commitment.turnNumber >= channel.turnNumber[commitment.signer] validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(commitment) == @@ -248,13 +252,13 @@ Refutable(n) == TRUE /\ n > channel.challenge.turnNumber -vars == << channel, challenge, pc >> +vars == << channel, submittedTX, pc >> ProcSet == {"Adjudicator"} \cup {Alice} \cup {Eve} Init == (* Global variables *) /\ channel = [turnNumber |-> [p \in ParticipantIDXs |-> 0], mode |-> ChannelMode.OPEN, challenge |-> NULL ] - /\ challenge = NULL + /\ submittedTX = NULL /\ pc = [self \in ProcSet |-> CASE self = "Adjudicator" -> "Adjudicator" [] self = Alice -> "AliceMoves" [] self = Eve -> "EveMoves"] @@ -262,19 +266,16 @@ Init == (* Global variables *) Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" /\ IF \/ AliceCanTakeAction \/ EveCanTakeAction - THEN /\ pc' = [pc EXCEPT !["Adjudicator"] = "HandleChallenge"] + THEN /\ IF submittedTX # NULL + THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> submittedTX.commitment ] @@ channel + /\ submittedTX' = NULL + ELSE /\ TRUE + /\ UNCHANGED << channel, submittedTX >> + /\ pc' = [pc EXCEPT !["Adjudicator"] = "Adjudicator"] ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "Done"] - /\ UNCHANGED << channel, challenge >> - -HandleChallenge == /\ pc["Adjudicator"] = "HandleChallenge" - /\ IF challenge # NULL - THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> challenge ] @@ channel - /\ challenge' = NULL - ELSE /\ TRUE - /\ UNCHANGED << channel, challenge >> - /\ pc' = [pc EXCEPT !["Adjudicator"] = "Adjudicator"] + /\ UNCHANGED << channel, submittedTX >> -adjudicator == Adjudicator \/ HandleChallenge +adjudicator == Adjudicator AliceMoves == /\ pc[Alice] = "AliceMoves" /\ IF AliceCanTakeAction @@ -285,20 +286,22 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" /\ AlicesMove(channel.challenge.turnNumber+1) THEN /\ pc' = [pc EXCEPT ![Alice] = "Respond_"] ELSE /\ pc' = [pc EXCEPT ![Alice] = "Finalize"] - /\ UNCHANGED challenge - ELSE /\ IF challenge = NULL + /\ UNCHANGED submittedTX + ELSE /\ IF submittedTX # NULL THEN /\ Assert(validCommitment(([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ])), - "Failure of assertion at line 111, column 1 of macro called at line 175, column 9.") + "Failure of assertion at line 117, column 1 of macro called at line 181, column 9.") /\ IF /\ channelOpen /\ progressesChannel(([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ])) - THEN /\ challenge' = [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ] + THEN /\ Assert(submittedTX = NULL, + "Failure of assertion at line 77, column 1 of macro called at line 181, column 9.") + /\ submittedTX' = [ commitment |-> ([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]), type |-> TX_Type.FORCE_MOVE ] ELSE /\ TRUE - /\ UNCHANGED challenge + /\ UNCHANGED submittedTX ELSE /\ TRUE - /\ UNCHANGED challenge + /\ UNCHANGED submittedTX /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] - /\ UNCHANGED challenge + /\ UNCHANGED submittedTX /\ UNCHANGED channel Refute_ == /\ pc[Alice] = "Refute_" @@ -312,24 +315,28 @@ Refute_ == /\ pc[Alice] = "Refute_" ELSE /\ TRUE /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED challenge + /\ UNCHANGED submittedTX Respond_ == /\ pc[Alice] = "Respond_" /\ IF /\ challengeOngoing /\ validTransition(([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ])) THEN /\ Assert((([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber) \in Nat, - "Failure of assertion at line 64, column 1 of macro called at line 168, column 17.") - /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber))], challenge |-> NULL ] + "Failure of assertion at line 66, column 1 of macro called at line 174, column 17.") + /\ channel' = [ + mode |-> ChannelMode.OPEN, + turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber))], + challenge |-> NULL + ] ELSE /\ Assert(FALSE, - "Failure of assertion at line 82, column 5 of macro called at line 168, column 17.") + "Failure of assertion at line 88, column 5 of macro called at line 174, column 17.") /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED challenge + /\ UNCHANGED submittedTX Finalize == /\ pc[Alice] = "Finalize" /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED challenge + /\ UNCHANGED submittedTX alice == AliceMoves \/ Refute_ \/ Respond_ \/ Finalize @@ -339,18 +346,20 @@ EveMoves == /\ pc[Eve] = "EveMoves" \/ /\ pc' = [pc EXCEPT ![Eve] = "Respond"] \/ /\ pc' = [pc EXCEPT ![Eve] = "Refute"] ELSE /\ pc' = [pc EXCEPT ![Eve] = "Done"] - /\ UNCHANGED << channel, challenge >> + /\ UNCHANGED << channel, submittedTX >> ForceMove == /\ pc[Eve] = "ForceMove" /\ \E n \in NumParticipants..LatestTurnNumber: \E idx \in ParticipantIDXs \ { AlicesIDX }: /\ Assert(validCommitment(([ turnNumber |-> n, signer |-> idx ])), - "Failure of assertion at line 111, column 1 of macro called at line 199, column 13.") + "Failure of assertion at line 117, column 1 of macro called at line 207, column 13.") /\ IF /\ channelOpen /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ])) - THEN /\ challenge' = [ turnNumber |-> n, signer |-> idx ] + THEN /\ Assert(submittedTX = NULL, + "Failure of assertion at line 77, column 1 of macro called at line 207, column 13.") + /\ submittedTX' = [ commitment |-> ([ turnNumber |-> n, signer |-> idx ]), type |-> TX_Type.FORCE_MOVE ] ELSE /\ TRUE - /\ UNCHANGED challenge + /\ UNCHANGED submittedTX /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] /\ UNCHANGED channel @@ -360,7 +369,7 @@ Respond == /\ pc[Eve] = "Respond" THEN /\ TRUE ELSE /\ TRUE /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] - /\ UNCHANGED << channel, challenge >> + /\ UNCHANGED << channel, submittedTX >> Refute == /\ pc[Eve] = "Refute" /\ IF /\ challengeOngoing @@ -368,7 +377,7 @@ Refute == /\ pc[Eve] = "Refute" THEN /\ TRUE ELSE /\ TRUE /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] - /\ UNCHANGED << channel, challenge >> + /\ UNCHANGED << channel, submittedTX >> eve == EveMoves \/ ForceMove \/ Respond \/ Refute @@ -389,14 +398,18 @@ Termination == <>(\A self \in ProcSet: pc[self] = "Done") \* END TRANSLATION AllowedTurnNumbers == 0..(StartingTurnNumber + NumParticipants) -AllowedChallenges == [ turnNumber: AllowedTurnNumbers, signer: ParticipantIDXs ] \cup { NULL } -AllowedChannels == [ turnNumber: [ParticipantIDXs -> Nat] , mode: Range(ChannelMode), challenge: AllowedChallenges ] +AllowedCommitments == [ turnNumber: AllowedTurnNumbers, signer: ParticipantIDXs ] + +AllowedTransactions == { NULL } + \cup [ type: { TX_Type.FORCE_MOVE }, commitment: AllowedCommitments ] + +AllowedChannels == [ turnNumber: [ParticipantIDXs -> Nat] , mode: Range(ChannelMode), challenge: AllowedCommitments \cup { NULL } ] \* Safety properties TypeOK == - /\ channel \in AllowedChannels - /\ challenge \in AllowedChallenges + /\ channel \in AllowedChannels + /\ submittedTX \in AllowedTransactions \* Liveness properties AliceCanProgressChannel == <>[]( @@ -413,13 +426,8 @@ AliceDoesNotLoseFunds == \/ AliceCanProgressChannel \/ FinalizedWithLatestTurnNumber -\* By checking this property, we can verify Alice's ability to front-run and replace Alice's pending challenge with another challenge. -EveDoesNotFrontRunChallenges == [][ - \/ challenge = NULL - \/ challenge' = NULL -]_<> ============================================================================= \* Modification History -\* Last modified Thu Sep 05 18:46:25 PDT 2019 by andrewstewart +\* Last modified Mon Sep 09 15:12:19 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 30105c5809e3e3b994ba9fd05feff7b7407fe93b Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Mon, 9 Sep 2019 15:20:10 -0600 Subject: [PATCH 35/66] wip --- ForceMove/ForceMove.tla | 68 ++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index dbcb145..37dbb48 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -38,7 +38,7 @@ ASSUME /\ AlicesIDX \in ParticipantIDXs /\ ~AlicesMove(LatestTurnNumber + 1) -(* --algorithm forceMove +(* --algorithm submitForceMove variables channel = [turnNumber |-> [p \in ParticipantIDXs |-> 0], mode |-> ChannelMode.OPEN, challenge |-> NULL ], @@ -71,13 +71,6 @@ channel := [ ]; end macro; - -macro submitChallenge(commitment) -begin -assert submittedTX = NULL; -submittedTX := [ commitment |-> commitment, type |-> TX_Type.FORCE_MOVE ]; -end macro; - macro respondWithMove(commitment) begin if @@ -114,13 +107,18 @@ end macro; macro forceMove(commitment) begin -assert validCommitment(commitment); if /\ channelOpen /\ progressesChannel(commitment) -then submitChallenge(commitment) +then + channel := [ mode |-> ChannelMode.CHALLENGE, challenge |-> commitment ] @@ channel; end if; +end macro; +macro submitForceMove(commitment) +begin +assert submittedTX = NULL; +submittedTX := [ commitment |-> commitment, type |-> TX_Type.FORCE_MOVE ]; end macro; fair process adjudicator = "Adjudicator" @@ -134,7 +132,7 @@ while \/ EveCanTakeAction do if submittedTX # NULL then - channel := [ mode |-> ChannelMode.CHALLENGE, challenge |-> submittedTX.commitment ] @@ channel; + forceMove(submittedTX.commitment); submittedTX := NULL; end if; end while; @@ -147,7 +145,7 @@ begin (* up with commitments (n - numParticipants + 1)..n. *) (* *) (* She is allowed to: *) -(* - Call forceMove with any states that she currently has *) +(* - Call submitForceMove with any states that she currently has *) (* - Call refute with any state that she has *) (* - Call respondWithMove or respondWithMove whenever there's an active *) (* challenge where it's her turn to move *) @@ -178,7 +176,7 @@ do channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel; end if; elsif submittedTX # NULL then - forceMove([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]); + submitForceMove([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]); end if; end while; end process; @@ -231,8 +229,8 @@ end algorithm; \* BEGIN TRANSLATION -\* Label Refute of process alice at line 103 col 1 changed to Refute_ -\* Label Respond of process alice at line 83 col 1 changed to Respond_ +\* Label Refute of process alice at line 96 col 1 changed to Refute_ +\* Label Respond of process alice at line 76 col 1 changed to Respond_ VARIABLES channel, submittedTX, pc (* define statement *) @@ -267,7 +265,11 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" /\ IF \/ AliceCanTakeAction \/ EveCanTakeAction THEN /\ IF submittedTX # NULL - THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> submittedTX.commitment ] @@ channel + THEN /\ IF /\ channelOpen + /\ progressesChannel((submittedTX.commitment)) + THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> (submittedTX.commitment) ] @@ channel + ELSE /\ TRUE + /\ UNCHANGED channel /\ submittedTX' = NULL ELSE /\ TRUE /\ UNCHANGED << channel, submittedTX >> @@ -288,15 +290,9 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" ELSE /\ pc' = [pc EXCEPT ![Alice] = "Finalize"] /\ UNCHANGED submittedTX ELSE /\ IF submittedTX # NULL - THEN /\ Assert(validCommitment(([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ])), - "Failure of assertion at line 117, column 1 of macro called at line 181, column 9.") - /\ IF /\ channelOpen - /\ progressesChannel(([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ])) - THEN /\ Assert(submittedTX = NULL, - "Failure of assertion at line 77, column 1 of macro called at line 181, column 9.") - /\ submittedTX' = [ commitment |-> ([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]), type |-> TX_Type.FORCE_MOVE ] - ELSE /\ TRUE - /\ UNCHANGED submittedTX + THEN /\ Assert(submittedTX = NULL, + "Failure of assertion at line 120, column 1 of macro called at line 179, column 9.") + /\ submittedTX' = [ commitment |-> ([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]), type |-> TX_Type.FORCE_MOVE ] ELSE /\ TRUE /\ UNCHANGED submittedTX /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] @@ -321,14 +317,14 @@ Respond_ == /\ pc[Alice] = "Respond_" /\ IF /\ challengeOngoing /\ validTransition(([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ])) THEN /\ Assert((([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber) \in Nat, - "Failure of assertion at line 66, column 1 of macro called at line 174, column 17.") + "Failure of assertion at line 66, column 1 of macro called at line 172, column 17.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber))], challenge |-> NULL ] ELSE /\ Assert(FALSE, - "Failure of assertion at line 88, column 5 of macro called at line 174, column 17.") + "Failure of assertion at line 81, column 5 of macro called at line 172, column 17.") /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED submittedTX @@ -351,17 +347,13 @@ EveMoves == /\ pc[Eve] = "EveMoves" ForceMove == /\ pc[Eve] = "ForceMove" /\ \E n \in NumParticipants..LatestTurnNumber: \E idx \in ParticipantIDXs \ { AlicesIDX }: - /\ Assert(validCommitment(([ turnNumber |-> n, signer |-> idx ])), - "Failure of assertion at line 117, column 1 of macro called at line 207, column 13.") - /\ IF /\ channelOpen - /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ])) - THEN /\ Assert(submittedTX = NULL, - "Failure of assertion at line 77, column 1 of macro called at line 207, column 13.") - /\ submittedTX' = [ commitment |-> ([ turnNumber |-> n, signer |-> idx ]), type |-> TX_Type.FORCE_MOVE ] - ELSE /\ TRUE - /\ UNCHANGED submittedTX + IF /\ channelOpen + /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ])) + THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> ([ turnNumber |-> n, signer |-> idx ]) ] @@ channel + ELSE /\ TRUE + /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] - /\ UNCHANGED channel + /\ UNCHANGED submittedTX Respond == /\ pc[Eve] = "Respond" /\ IF /\ challengeOngoing @@ -429,5 +421,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Mon Sep 09 15:12:19 MDT 2019 by andrewstewart +\* Last modified Mon Sep 09 15:19:03 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 2026b90fbbf3a87c96b4f33fd743d0574f4d77f7 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Mon, 9 Sep 2019 15:28:09 -0600 Subject: [PATCH 36/66] wip: Eve can instantly mine transactions --- ForceMove/ForceMove.tla | 115 ++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 74 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 37dbb48..4197af1 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -198,29 +198,19 @@ begin (***************************************************************************) EveMoves: while EveCanTakeAction do - either ForceMove: +\* either ForceMove: with n \in NumParticipants..LatestTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } do forceMove([ turnNumber |-> n, signer |-> idx ]); end with; - or Respond: - if - /\ challengeOngoing - /\ ~AlicesMove(channel.challenge.turnNumber) - then skip; +\* or Respond: skip; \* respondWithMove([ \* turnNumber |-> channel.challenge.turnNumber + 1, \* signer |-> ParticipantIDX(channel.challenge.turnNumber) \* ]); - end if; - or Refute: - if - /\ challengeOngoing - /\ ~AlicesMove(channel.challenge.turnNumber) - then skip; - end if; - end either; +\* or Refute: skip; +\* end either; end while; end process; @@ -229,8 +219,6 @@ end algorithm; \* BEGIN TRANSLATION -\* Label Refute of process alice at line 96 col 1 changed to Refute_ -\* Label Respond of process alice at line 76 col 1 changed to Respond_ VARIABLES channel, submittedTX, pc (* define statement *) @@ -283,10 +271,10 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" /\ IF AliceCanTakeAction THEN /\ IF challengeOngoing THEN /\ IF /\ channel.challenge.turnNumber < StartingTurnNumber - THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute_"] + THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute"] ELSE /\ IF /\ channel.challenge.turnNumber >= StartingTurnNumber /\ AlicesMove(channel.challenge.turnNumber+1) - THEN /\ pc' = [pc EXCEPT ![Alice] = "Respond_"] + THEN /\ pc' = [pc EXCEPT ![Alice] = "Respond"] ELSE /\ pc' = [pc EXCEPT ![Alice] = "Finalize"] /\ UNCHANGED submittedTX ELSE /\ IF submittedTX # NULL @@ -300,78 +288,57 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" /\ UNCHANGED submittedTX /\ UNCHANGED channel -Refute_ == /\ pc[Alice] = "Refute_" +Refute == /\ pc[Alice] = "Refute" + /\ IF /\ challengeOngoing + /\ (CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer) > channel.turnNumber[ParticipantIDX((CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer))] + THEN /\ channel' = [ + mode |-> ChannelMode.OPEN, + challenge |-> NULL, + turnNumber |-> [i \in {ParticipantIDX((CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer))} |-> (CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer)] @@ channel.turnNumber + ] + ELSE /\ TRUE + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + /\ UNCHANGED submittedTX + +Respond == /\ pc[Alice] = "Respond" /\ IF /\ challengeOngoing - /\ (CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer) > channel.turnNumber[ParticipantIDX((CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer))] - THEN /\ channel' = [ + /\ validTransition(([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ])) + THEN /\ Assert((([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber) \in Nat, + "Failure of assertion at line 66, column 1 of macro called at line 172, column 17.") + /\ channel' = [ mode |-> ChannelMode.OPEN, - challenge |-> NULL, - turnNumber |-> [i \in {ParticipantIDX((CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer))} |-> (CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer)] @@ channel.turnNumber + turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber))], + challenge |-> NULL ] - ELSE /\ TRUE + ELSE /\ Assert(FALSE, + "Failure of assertion at line 81, column 5 of macro called at line 172, column 17.") /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED submittedTX -Respond_ == /\ pc[Alice] = "Respond_" - /\ IF /\ challengeOngoing - /\ validTransition(([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ])) - THEN /\ Assert((([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber) \in Nat, - "Failure of assertion at line 66, column 1 of macro called at line 172, column 17.") - /\ channel' = [ - mode |-> ChannelMode.OPEN, - turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber))], - challenge |-> NULL - ] - ELSE /\ Assert(FALSE, - "Failure of assertion at line 81, column 5 of macro called at line 172, column 17.") - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED submittedTX - Finalize == /\ pc[Alice] = "Finalize" /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED submittedTX -alice == AliceMoves \/ Refute_ \/ Respond_ \/ Finalize +alice == AliceMoves \/ Refute \/ Respond \/ Finalize EveMoves == /\ pc[Eve] = "EveMoves" /\ IF EveCanTakeAction - THEN /\ \/ /\ pc' = [pc EXCEPT ![Eve] = "ForceMove"] - \/ /\ pc' = [pc EXCEPT ![Eve] = "Respond"] - \/ /\ pc' = [pc EXCEPT ![Eve] = "Refute"] + THEN /\ \E n \in NumParticipants..LatestTurnNumber: + \E idx \in ParticipantIDXs \ { AlicesIDX }: + IF /\ channelOpen + /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ])) + THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> ([ turnNumber |-> n, signer |-> idx ]) ] @@ channel + ELSE /\ TRUE + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] ELSE /\ pc' = [pc EXCEPT ![Eve] = "Done"] - /\ UNCHANGED << channel, submittedTX >> - -ForceMove == /\ pc[Eve] = "ForceMove" - /\ \E n \in NumParticipants..LatestTurnNumber: - \E idx \in ParticipantIDXs \ { AlicesIDX }: - IF /\ channelOpen - /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ])) - THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> ([ turnNumber |-> n, signer |-> idx ]) ] @@ channel - ELSE /\ TRUE - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] - /\ UNCHANGED submittedTX - -Respond == /\ pc[Eve] = "Respond" - /\ IF /\ challengeOngoing - /\ ~AlicesMove(channel.challenge.turnNumber) - THEN /\ TRUE - ELSE /\ TRUE - /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] - /\ UNCHANGED << channel, submittedTX >> - -Refute == /\ pc[Eve] = "Refute" - /\ IF /\ challengeOngoing - /\ ~AlicesMove(channel.challenge.turnNumber) - THEN /\ TRUE - ELSE /\ TRUE - /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] - /\ UNCHANGED << channel, submittedTX >> + /\ UNCHANGED channel + /\ UNCHANGED submittedTX -eve == EveMoves \/ ForceMove \/ Respond \/ Refute +eve == EveMoves (* Allow infinite stuttering to prevent deadlock on termination. *) Terminating == /\ \A self \in ProcSet: pc[self] = "Done" @@ -421,5 +388,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Mon Sep 09 15:19:03 MDT 2019 by andrewstewart +\* Last modified Mon Sep 09 15:22:49 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 93038f6da3466d8cf537275f5d7c22c4c7347c38 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Mon, 9 Sep 2019 15:36:59 -0600 Subject: [PATCH 37/66] Add effect that can exhibit infinite griefing --- ForceMove/ForceMove.tla | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 4197af1..ce7f233 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -100,7 +100,8 @@ then channel := [ mode |-> ChannelMode.OPEN, challenge |-> NULL, - turnNumber |-> [i \in {ParticipantIDX(turnNumber)} |-> turnNumber] @@ channel.turnNumber + turnNumber |-> [i \in {ParticipantIDX(turnNumber)} |-> turnNumber] @@ channel.turnNumber +\* turnNumber |-> channel.turnNumber \* With this effect, eve can infinitely grief ]; end if; end macro; @@ -279,7 +280,7 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" /\ UNCHANGED submittedTX ELSE /\ IF submittedTX # NULL THEN /\ Assert(submittedTX = NULL, - "Failure of assertion at line 120, column 1 of macro called at line 179, column 9.") + "Failure of assertion at line 121, column 1 of macro called at line 180, column 9.") /\ submittedTX' = [ commitment |-> ([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]), type |-> TX_Type.FORCE_MOVE ] ELSE /\ TRUE /\ UNCHANGED submittedTX @@ -295,6 +296,7 @@ Refute == /\ pc[Alice] = "Refute" mode |-> ChannelMode.OPEN, challenge |-> NULL, turnNumber |-> [i \in {ParticipantIDX((CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer))} |-> (CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer)] @@ channel.turnNumber + ] ELSE /\ TRUE /\ UNCHANGED channel @@ -305,14 +307,14 @@ Respond == /\ pc[Alice] = "Respond" /\ IF /\ challengeOngoing /\ validTransition(([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ])) THEN /\ Assert((([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber) \in Nat, - "Failure of assertion at line 66, column 1 of macro called at line 172, column 17.") + "Failure of assertion at line 66, column 1 of macro called at line 173, column 17.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber))], challenge |-> NULL ] ELSE /\ Assert(FALSE, - "Failure of assertion at line 81, column 5 of macro called at line 172, column 17.") + "Failure of assertion at line 81, column 5 of macro called at line 173, column 17.") /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED submittedTX @@ -388,5 +390,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Mon Sep 09 15:22:49 MDT 2019 by andrewstewart +\* Last modified Mon Sep 09 15:36:18 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 2bdb120ba7100e33c2bda1b9dfa7882bc66ef756 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Mon, 9 Sep 2019 15:50:28 -0600 Subject: [PATCH 38/66] Alice submits refutes --- ForceMove/ForceMove.tla | 75 +++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index ce7f233..173865b 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -16,7 +16,8 @@ ChannelMode == [ TX_Type == [ - FORCE_MOVE |-> "FORCE_MOVE" + FORCE_MOVE |-> "FORCE_MOVE", + REFUTE |-> "REFUTE" ] Range(f) == { f[x] : x \in DOMAIN f } @@ -122,6 +123,12 @@ assert submittedTX = NULL; submittedTX := [ commitment |-> commitment, type |-> TX_Type.FORCE_MOVE ]; end macro; +macro submitRefute(turnNumber) +begin +assert submittedTX = NULL; +submittedTX := [ turnNumber |-> turnNumber, type |-> TX_Type.REFUTE ]; +end macro; + fair process adjudicator = "Adjudicator" begin (***************************************************************************) @@ -133,7 +140,10 @@ while \/ EveCanTakeAction do if submittedTX # NULL then - forceMove(submittedTX.commitment); + if submittedTX.type = TX_Type.FORCE_MOVE then forceMove(submittedTX.commitment); + elsif submittedTX.type = TX_Type.REFUTE then refute(submittedTX.turnNumber); + else assert FALSE; + end if; submittedTX := NULL; end if; end while; @@ -157,12 +167,13 @@ do if challengeOngoing then if /\ channel.challenge.turnNumber < StartingTurnNumber + /\ submittedTX = NULL then \* Alice has signed commitments from StartingTurnNumber up to LastTurnNumber. \* She can therefore call refute with exactly one commitment, according to \* the channel's current turnNumber. Refute: - refute( + submitRefute( CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer ); elsif @@ -171,8 +182,8 @@ do then Respond: respondWithMove([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]); - else - \* Alice has run out of allowed actions, resulting in the channel being finalized + elsif submittedTX = NULL + then \* Alice has run out of allowed actions, resulting in the channel being finalized Finalize: channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel; end if; @@ -254,11 +265,26 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" /\ IF \/ AliceCanTakeAction \/ EveCanTakeAction THEN /\ IF submittedTX # NULL - THEN /\ IF /\ channelOpen - /\ progressesChannel((submittedTX.commitment)) - THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> (submittedTX.commitment) ] @@ channel - ELSE /\ TRUE - /\ UNCHANGED channel + THEN /\ IF submittedTX.type = TX_Type.FORCE_MOVE + THEN /\ IF /\ channelOpen + /\ progressesChannel((submittedTX.commitment)) + THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> (submittedTX.commitment) ] @@ channel + ELSE /\ TRUE + /\ UNCHANGED channel + ELSE /\ IF submittedTX.type = TX_Type.REFUTE + THEN /\ IF /\ challengeOngoing + /\ (submittedTX.turnNumber) > channel.turnNumber[ParticipantIDX((submittedTX.turnNumber))] + THEN /\ channel' = [ + mode |-> ChannelMode.OPEN, + challenge |-> NULL, + turnNumber |-> [i \in {ParticipantIDX((submittedTX.turnNumber))} |-> (submittedTX.turnNumber)] @@ channel.turnNumber + + ] + ELSE /\ TRUE + /\ UNCHANGED channel + ELSE /\ Assert(FALSE, + "Failure of assertion at line 145, column 14.") + /\ UNCHANGED channel /\ submittedTX' = NULL ELSE /\ TRUE /\ UNCHANGED << channel, submittedTX >> @@ -272,15 +298,18 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" /\ IF AliceCanTakeAction THEN /\ IF challengeOngoing THEN /\ IF /\ channel.challenge.turnNumber < StartingTurnNumber + /\ submittedTX = NULL THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute"] ELSE /\ IF /\ channel.challenge.turnNumber >= StartingTurnNumber /\ AlicesMove(channel.challenge.turnNumber+1) THEN /\ pc' = [pc EXCEPT ![Alice] = "Respond"] - ELSE /\ pc' = [pc EXCEPT ![Alice] = "Finalize"] + ELSE /\ IF submittedTX = NULL + THEN /\ pc' = [pc EXCEPT ![Alice] = "Finalize"] + ELSE /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED submittedTX ELSE /\ IF submittedTX # NULL THEN /\ Assert(submittedTX = NULL, - "Failure of assertion at line 121, column 1 of macro called at line 180, column 9.") + "Failure of assertion at line 122, column 1 of macro called at line 191, column 9.") /\ submittedTX' = [ commitment |-> ([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]), type |-> TX_Type.FORCE_MOVE ] ELSE /\ TRUE /\ UNCHANGED submittedTX @@ -290,31 +319,24 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" /\ UNCHANGED channel Refute == /\ pc[Alice] = "Refute" - /\ IF /\ challengeOngoing - /\ (CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer) > channel.turnNumber[ParticipantIDX((CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer))] - THEN /\ channel' = [ - mode |-> ChannelMode.OPEN, - challenge |-> NULL, - turnNumber |-> [i \in {ParticipantIDX((CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer))} |-> (CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer)] @@ channel.turnNumber - - ] - ELSE /\ TRUE - /\ UNCHANGED channel + /\ Assert(submittedTX = NULL, + "Failure of assertion at line 128, column 1 of macro called at line 176, column 17.") + /\ submittedTX' = [ turnNumber |-> (CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer), type |-> TX_Type.REFUTE ] /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED submittedTX + /\ UNCHANGED channel Respond == /\ pc[Alice] = "Respond" /\ IF /\ challengeOngoing /\ validTransition(([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ])) THEN /\ Assert((([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber) \in Nat, - "Failure of assertion at line 66, column 1 of macro called at line 173, column 17.") + "Failure of assertion at line 67, column 1 of macro called at line 184, column 17.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber))], challenge |-> NULL ] ELSE /\ Assert(FALSE, - "Failure of assertion at line 81, column 5 of macro called at line 173, column 17.") + "Failure of assertion at line 82, column 5 of macro called at line 184, column 17.") /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED submittedTX @@ -363,6 +385,7 @@ AllowedCommitments == [ turnNumber: AllowedTurnNumbers, signer: ParticipantIDXs AllowedTransactions == { NULL } \cup [ type: { TX_Type.FORCE_MOVE }, commitment: AllowedCommitments ] + \cup [ type: { TX_Type.REFUTE }, turnNumber: AllowedTurnNumbers ] AllowedChannels == [ turnNumber: [ParticipantIDXs -> Nat] , mode: Range(ChannelMode), challenge: AllowedCommitments \cup { NULL } ] @@ -390,5 +413,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Mon Sep 09 15:36:18 MDT 2019 by andrewstewart +\* Last modified Mon Sep 09 15:50:09 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 2839037302dbb2db460d838ddd59c05ae6f7da0c Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Mon, 9 Sep 2019 16:00:46 -0600 Subject: [PATCH 39/66] Simplify alice's process --- ForceMove/ForceMove.tla | 97 +++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 173865b..2219db6 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -117,18 +117,6 @@ then end if; end macro; -macro submitForceMove(commitment) -begin -assert submittedTX = NULL; -submittedTX := [ commitment |-> commitment, type |-> TX_Type.FORCE_MOVE ]; -end macro; - -macro submitRefute(turnNumber) -begin -assert submittedTX = NULL; -submittedTX := [ turnNumber |-> turnNumber, type |-> TX_Type.REFUTE ]; -end macro; - fair process adjudicator = "Adjudicator" begin (***************************************************************************) @@ -164,31 +152,40 @@ begin AliceMoves: while AliceCanTakeAction do - if challengeOngoing then + if + /\ submittedTX = NULL + /\ challengeOngoing + then if /\ channel.challenge.turnNumber < StartingTurnNumber /\ submittedTX = NULL - then + then SubmitRefute: \* Alice has signed commitments from StartingTurnNumber up to LastTurnNumber. \* She can therefore call refute with exactly one commitment, according to \* the channel's current turnNumber. - Refute: - submitRefute( - CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer - ); + submittedTX := [ + turnNumber |-> CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer, + type |-> TX_Type.REFUTE + ]; elsif /\ channel.challenge.turnNumber >= StartingTurnNumber /\ AlicesMove(channel.challenge.turnNumber+1) then Respond: respondWithMove([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]); - elsif submittedTX = NULL - then \* Alice has run out of allowed actions, resulting in the channel being finalized + else + \* Alice has run out of allowed actions, resulting in the channel being finalized Finalize: channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel; end if; - elsif submittedTX # NULL then - submitForceMove([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]); + elsif + /\ submittedTX = NULL + /\ ~challengeOngoing + then SubmitForceMove: + submittedTX := [ + commitment |-> [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ], + type |-> TX_Type.FORCE_MOVE + ]; end if; end while; end process; @@ -283,7 +280,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" ELSE /\ TRUE /\ UNCHANGED channel ELSE /\ Assert(FALSE, - "Failure of assertion at line 145, column 14.") + "Failure of assertion at line 133, column 14.") /\ UNCHANGED channel /\ submittedTX' = NULL ELSE /\ TRUE @@ -296,47 +293,42 @@ adjudicator == Adjudicator AliceMoves == /\ pc[Alice] = "AliceMoves" /\ IF AliceCanTakeAction - THEN /\ IF challengeOngoing + THEN /\ IF /\ submittedTX = NULL + /\ challengeOngoing THEN /\ IF /\ channel.challenge.turnNumber < StartingTurnNumber /\ submittedTX = NULL - THEN /\ pc' = [pc EXCEPT ![Alice] = "Refute"] + THEN /\ pc' = [pc EXCEPT ![Alice] = "SubmitRefute"] ELSE /\ IF /\ channel.challenge.turnNumber >= StartingTurnNumber /\ AlicesMove(channel.challenge.turnNumber+1) THEN /\ pc' = [pc EXCEPT ![Alice] = "Respond"] - ELSE /\ IF submittedTX = NULL - THEN /\ pc' = [pc EXCEPT ![Alice] = "Finalize"] - ELSE /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED submittedTX - ELSE /\ IF submittedTX # NULL - THEN /\ Assert(submittedTX = NULL, - "Failure of assertion at line 122, column 1 of macro called at line 191, column 9.") - /\ submittedTX' = [ commitment |-> ([ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ]), type |-> TX_Type.FORCE_MOVE ] - ELSE /\ TRUE - /\ UNCHANGED submittedTX - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + ELSE /\ pc' = [pc EXCEPT ![Alice] = "Finalize"] + ELSE /\ IF /\ submittedTX = NULL + /\ ~challengeOngoing + THEN /\ pc' = [pc EXCEPT ![Alice] = "SubmitForceMove"] + ELSE /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] - /\ UNCHANGED submittedTX - /\ UNCHANGED channel + /\ UNCHANGED << channel, submittedTX >> -Refute == /\ pc[Alice] = "Refute" - /\ Assert(submittedTX = NULL, - "Failure of assertion at line 128, column 1 of macro called at line 176, column 17.") - /\ submittedTX' = [ turnNumber |-> (CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer), type |-> TX_Type.REFUTE ] - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED channel +SubmitRefute == /\ pc[Alice] = "SubmitRefute" + /\ submittedTX' = [ + turnNumber |-> CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer, + type |-> TX_Type.REFUTE + ] + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + /\ UNCHANGED channel Respond == /\ pc[Alice] = "Respond" /\ IF /\ challengeOngoing /\ validTransition(([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ])) THEN /\ Assert((([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber) \in Nat, - "Failure of assertion at line 67, column 1 of macro called at line 184, column 17.") + "Failure of assertion at line 67, column 1 of macro called at line 175, column 17.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber))], challenge |-> NULL ] ELSE /\ Assert(FALSE, - "Failure of assertion at line 82, column 5 of macro called at line 184, column 17.") + "Failure of assertion at line 82, column 5 of macro called at line 175, column 17.") /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED submittedTX @@ -346,7 +338,16 @@ Finalize == /\ pc[Alice] = "Finalize" /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED submittedTX -alice == AliceMoves \/ Refute \/ Respond \/ Finalize +SubmitForceMove == /\ pc[Alice] = "SubmitForceMove" + /\ submittedTX' = [ + commitment |-> [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ], + type |-> TX_Type.FORCE_MOVE + ] + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + /\ UNCHANGED channel + +alice == AliceMoves \/ SubmitRefute \/ Respond \/ Finalize + \/ SubmitForceMove EveMoves == /\ pc[Eve] = "EveMoves" /\ IF EveCanTakeAction @@ -413,5 +414,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Mon Sep 09 15:50:09 MDT 2019 by andrewstewart +\* Last modified Mon Sep 09 16:00:23 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From bbb2c76bbda3d7f02277e7e0d4c24b4ea5c1dd0a Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Mon, 9 Sep 2019 17:08:03 -0600 Subject: [PATCH 40/66] Alice submits respond transactions --- ForceMove/ForceMove.tla | 70 ++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 2219db6..b3fe686 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -17,7 +17,8 @@ ChannelMode == [ TX_Type == [ FORCE_MOVE |-> "FORCE_MOVE", - REFUTE |-> "REFUTE" + REFUTE |-> "REFUTE", + RESPOND |-> "RESPOND" ] Range(f) == { f[x] : x \in DOMAIN f } @@ -130,6 +131,7 @@ do if submittedTX # NULL then if submittedTX.type = TX_Type.FORCE_MOVE then forceMove(submittedTX.commitment); elsif submittedTX.type = TX_Type.REFUTE then refute(submittedTX.turnNumber); + elsif submittedTX.type = TX_Type.RESPOND then respondWithMove(submittedTX.commitment); else assert FALSE; end if; submittedTX := NULL; @@ -163,16 +165,17 @@ do \* Alice has signed commitments from StartingTurnNumber up to LastTurnNumber. \* She can therefore call refute with exactly one commitment, according to \* the channel's current turnNumber. - submittedTX := [ - turnNumber |-> CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer, - type |-> TX_Type.REFUTE - ]; + with turnNumber = CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer + do submittedTX := [ type |-> TX_Type.REFUTE, turnNumber |-> turnNumber]; + end with; elsif /\ channel.challenge.turnNumber >= StartingTurnNumber /\ AlicesMove(channel.challenge.turnNumber+1) then - Respond: - respondWithMove([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]); + SubmitRespond: + with commitment = [ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ] + do submittedTX := [ type |-> TX_Type.RESPOND, commitment |-> commitment ]; + end with; else \* Alice has run out of allowed actions, resulting in the channel being finalized Finalize: @@ -279,9 +282,22 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" ] ELSE /\ TRUE /\ UNCHANGED channel - ELSE /\ Assert(FALSE, - "Failure of assertion at line 133, column 14.") - /\ UNCHANGED channel + ELSE /\ IF submittedTX.type = TX_Type.RESPOND + THEN /\ IF /\ challengeOngoing + /\ validTransition((submittedTX.commitment)) + THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, + "Failure of assertion at line 68, column 1 of macro called at line 134, column 58.") + /\ channel' = [ + mode |-> ChannelMode.OPEN, + turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], + challenge |-> NULL + ] + ELSE /\ Assert(FALSE, + "Failure of assertion at line 83, column 5 of macro called at line 134, column 58.") + /\ UNCHANGED channel + ELSE /\ Assert(FALSE, + "Failure of assertion at line 135, column 14.") + /\ UNCHANGED channel /\ submittedTX' = NULL ELSE /\ TRUE /\ UNCHANGED << channel, submittedTX >> @@ -300,7 +316,7 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" THEN /\ pc' = [pc EXCEPT ![Alice] = "SubmitRefute"] ELSE /\ IF /\ channel.challenge.turnNumber >= StartingTurnNumber /\ AlicesMove(channel.challenge.turnNumber+1) - THEN /\ pc' = [pc EXCEPT ![Alice] = "Respond"] + THEN /\ pc' = [pc EXCEPT ![Alice] = "SubmitRespond"] ELSE /\ pc' = [pc EXCEPT ![Alice] = "Finalize"] ELSE /\ IF /\ submittedTX = NULL /\ ~challengeOngoing @@ -310,28 +326,16 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" /\ UNCHANGED << channel, submittedTX >> SubmitRefute == /\ pc[Alice] = "SubmitRefute" - /\ submittedTX' = [ - turnNumber |-> CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer, - type |-> TX_Type.REFUTE - ] + /\ LET turnNumber == CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer IN + submittedTX' = [ type |-> TX_Type.REFUTE, turnNumber |-> turnNumber] /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED channel -Respond == /\ pc[Alice] = "Respond" - /\ IF /\ challengeOngoing - /\ validTransition(([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ])) - THEN /\ Assert((([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber) \in Nat, - "Failure of assertion at line 67, column 1 of macro called at line 175, column 17.") - /\ channel' = [ - mode |-> ChannelMode.OPEN, - turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (([ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ]).turnNumber))], - challenge |-> NULL - ] - ELSE /\ Assert(FALSE, - "Failure of assertion at line 82, column 5 of macro called at line 175, column 17.") - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED submittedTX +SubmitRespond == /\ pc[Alice] = "SubmitRespond" + /\ LET commitment == [ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ] IN + submittedTX' = [ type |-> TX_Type.RESPOND, commitment |-> commitment ] + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + /\ UNCHANGED channel Finalize == /\ pc[Alice] = "Finalize" /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel @@ -346,7 +350,7 @@ SubmitForceMove == /\ pc[Alice] = "SubmitForceMove" /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] /\ UNCHANGED channel -alice == AliceMoves \/ SubmitRefute \/ Respond \/ Finalize +alice == AliceMoves \/ SubmitRefute \/ SubmitRespond \/ Finalize \/ SubmitForceMove EveMoves == /\ pc[Eve] = "EveMoves" @@ -385,7 +389,7 @@ AllowedTurnNumbers == 0..(StartingTurnNumber + NumParticipants) AllowedCommitments == [ turnNumber: AllowedTurnNumbers, signer: ParticipantIDXs ] AllowedTransactions == { NULL } - \cup [ type: { TX_Type.FORCE_MOVE }, commitment: AllowedCommitments ] + \cup [ type: { TX_Type.FORCE_MOVE, TX_Type.RESPOND }, commitment: AllowedCommitments ] \cup [ type: { TX_Type.REFUTE }, turnNumber: AllowedTurnNumbers ] AllowedChannels == [ turnNumber: [ParticipantIDXs -> Nat] , mode: Range(ChannelMode), challenge: AllowedCommitments \cup { NULL } ] @@ -414,5 +418,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Mon Sep 09 16:00:23 MDT 2019 by andrewstewart +\* Last modified Mon Sep 09 16:06:04 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From f0de0397011ad9c533defcffb3a58f7dc6ccdaa4 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Mon, 9 Sep 2019 17:28:11 -0600 Subject: [PATCH 41/66] Eve responds --- ForceMove/ForceMove.tla | 147 +++++++++++++++++++++++----------------- 1 file changed, 83 insertions(+), 64 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index b3fe686..fa84569 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -55,7 +55,9 @@ validTransition(commitment) == /\ commitment.turnNumber = channel.challenge.turnNumber + 1 /\ commitment.signer = ParticipantIDX(commitment.turnNumber) -AliceCanTakeAction == channel.mode # ChannelMode.FINALIZED +AliceCanTakeAction == + /\ channel.mode # ChannelMode.FINALIZED + /\ channel.turnNumber[AlicesIDX] < AlicesGoalTurnNumber EveCanTakeAction == AliceCanTakeAction Refutable(n) == TRUE @@ -161,7 +163,7 @@ do if /\ channel.challenge.turnNumber < StartingTurnNumber /\ submittedTX = NULL - then SubmitRefute: + then \* Alice has signed commitments from StartingTurnNumber up to LastTurnNumber. \* She can therefore call refute with exactly one commitment, according to \* the channel's current turnNumber. @@ -172,19 +174,17 @@ do /\ channel.challenge.turnNumber >= StartingTurnNumber /\ AlicesMove(channel.challenge.turnNumber+1) then - SubmitRespond: with commitment = [ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ] do submittedTX := [ type |-> TX_Type.RESPOND, commitment |-> commitment ]; end with; else \* Alice has run out of allowed actions, resulting in the channel being finalized - Finalize: channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel; end if; elsif /\ submittedTX = NULL /\ ~challengeOngoing - then SubmitForceMove: + then submittedTX := [ commitment |-> [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ], type |-> TX_Type.FORCE_MOVE @@ -210,19 +210,23 @@ begin (***************************************************************************) EveMoves: while EveCanTakeAction do -\* either ForceMove: + either ForceMove: with n \in NumParticipants..LatestTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } do forceMove([ turnNumber |-> n, signer |-> idx ]); end with; -\* or Respond: skip; -\* respondWithMove([ -\* turnNumber |-> channel.challenge.turnNumber + 1, -\* signer |-> ParticipantIDX(channel.challenge.turnNumber) -\* ]); + or Respond: + if + /\ challengeOngoing + /\ ~AlicesMove(channel.challenge.turnNumber+1) + then with + turnNumber = channel.challenge.turnNumber + 1, + commitment = [ turnNumber |-> turnNumber, signer |-> ParticipantIDX(turnNumber)] + do respondWithMove(commitment); end with; + end if; \* or Refute: skip; -\* end either; + end either; end while; end process; @@ -242,7 +246,9 @@ validTransition(commitment) == /\ commitment.turnNumber = channel.challenge.turnNumber + 1 /\ commitment.signer = ParticipantIDX(commitment.turnNumber) -AliceCanTakeAction == channel.mode # ChannelMode.FINALIZED +AliceCanTakeAction == + /\ channel.mode # ChannelMode.FINALIZED + /\ channel.turnNumber[AlicesIDX] < AlicesGoalTurnNumber EveCanTakeAction == AliceCanTakeAction Refutable(n) == TRUE @@ -286,17 +292,18 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" THEN /\ IF /\ challengeOngoing /\ validTransition((submittedTX.commitment)) THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, - "Failure of assertion at line 68, column 1 of macro called at line 134, column 58.") + "Failure of assertion at line 70, column 1 of macro called at line 137, column 58.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], challenge |-> NULL ] - ELSE /\ Assert(FALSE, - "Failure of assertion at line 83, column 5 of macro called at line 134, column 58.") + ELSE /\ PrintT((<<(submittedTX.commitment), channel.challenge>>)) + /\ Assert(FALSE, + "Failure of assertion at line 86, column 5 of macro called at line 137, column 58.") /\ UNCHANGED channel ELSE /\ Assert(FALSE, - "Failure of assertion at line 135, column 14.") + "Failure of assertion at line 138, column 14.") /\ UNCHANGED channel /\ submittedTX' = NULL ELSE /\ TRUE @@ -313,61 +320,73 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" /\ challengeOngoing THEN /\ IF /\ channel.challenge.turnNumber < StartingTurnNumber /\ submittedTX = NULL - THEN /\ pc' = [pc EXCEPT ![Alice] = "SubmitRefute"] + THEN /\ LET turnNumber == CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer IN + submittedTX' = [ type |-> TX_Type.REFUTE, turnNumber |-> turnNumber] + /\ UNCHANGED channel ELSE /\ IF /\ channel.challenge.turnNumber >= StartingTurnNumber /\ AlicesMove(channel.challenge.turnNumber+1) - THEN /\ pc' = [pc EXCEPT ![Alice] = "SubmitRespond"] - ELSE /\ pc' = [pc EXCEPT ![Alice] = "Finalize"] + THEN /\ LET commitment == [ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ] IN + submittedTX' = [ type |-> TX_Type.RESPOND, commitment |-> commitment ] + /\ UNCHANGED channel + ELSE /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel + /\ UNCHANGED submittedTX ELSE /\ IF /\ submittedTX = NULL /\ ~challengeOngoing - THEN /\ pc' = [pc EXCEPT ![Alice] = "SubmitForceMove"] - ELSE /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + THEN /\ submittedTX' = [ + commitment |-> [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ], + type |-> TX_Type.FORCE_MOVE + ] + ELSE /\ TRUE + /\ UNCHANGED submittedTX + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] - /\ UNCHANGED << channel, submittedTX >> - -SubmitRefute == /\ pc[Alice] = "SubmitRefute" - /\ LET turnNumber == CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer IN - submittedTX' = [ type |-> TX_Type.REFUTE, turnNumber |-> turnNumber] - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED channel - -SubmitRespond == /\ pc[Alice] = "SubmitRespond" - /\ LET commitment == [ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ] IN - submittedTX' = [ type |-> TX_Type.RESPOND, commitment |-> commitment ] - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED channel - -Finalize == /\ pc[Alice] = "Finalize" - /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED submittedTX - -SubmitForceMove == /\ pc[Alice] = "SubmitForceMove" - /\ submittedTX' = [ - commitment |-> [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ], - type |-> TX_Type.FORCE_MOVE - ] - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED channel - -alice == AliceMoves \/ SubmitRefute \/ SubmitRespond \/ Finalize - \/ SubmitForceMove + /\ UNCHANGED << channel, submittedTX >> + +alice == AliceMoves EveMoves == /\ pc[Eve] = "EveMoves" /\ IF EveCanTakeAction - THEN /\ \E n \in NumParticipants..LatestTurnNumber: - \E idx \in ParticipantIDXs \ { AlicesIDX }: - IF /\ channelOpen - /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ])) - THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> ([ turnNumber |-> n, signer |-> idx ]) ] @@ channel - ELSE /\ TRUE - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] + THEN /\ \/ /\ pc' = [pc EXCEPT ![Eve] = "ForceMove"] + \/ /\ pc' = [pc EXCEPT ![Eve] = "Respond"] ELSE /\ pc' = [pc EXCEPT ![Eve] = "Done"] - /\ UNCHANGED channel - /\ UNCHANGED submittedTX - -eve == EveMoves + /\ UNCHANGED << channel, submittedTX >> + +ForceMove == /\ pc[Eve] = "ForceMove" + /\ \E n \in NumParticipants..LatestTurnNumber: + \E idx \in ParticipantIDXs \ { AlicesIDX }: + IF /\ channelOpen + /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ])) + THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> ([ turnNumber |-> n, signer |-> idx ]) ] @@ channel + ELSE /\ TRUE + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] + /\ UNCHANGED submittedTX + +Respond == /\ pc[Eve] = "Respond" + /\ IF /\ challengeOngoing + /\ ~AlicesMove(channel.challenge.turnNumber+1) + THEN /\ LET turnNumber == channel.challenge.turnNumber + 1 IN + LET commitment == [ turnNumber |-> turnNumber, signer |-> ParticipantIDX(turnNumber)] IN + IF /\ challengeOngoing + /\ validTransition(commitment) + THEN /\ Assert((commitment.turnNumber) \in Nat, + "Failure of assertion at line 70, column 1 of macro called at line 227, column 12.") + /\ channel' = [ + mode |-> ChannelMode.OPEN, + turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], + challenge |-> NULL + ] + ELSE /\ PrintT((<>)) + /\ Assert(FALSE, + "Failure of assertion at line 86, column 5 of macro called at line 227, column 12.") + /\ UNCHANGED channel + ELSE /\ TRUE + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] + /\ UNCHANGED submittedTX + +eve == EveMoves \/ ForceMove \/ Respond (* Allow infinite stuttering to prevent deadlock on termination. *) Terminating == /\ \A self \in ProcSet: pc[self] = "Done" @@ -418,5 +437,5 @@ AliceDoesNotLoseFunds == ============================================================================= \* Modification History -\* Last modified Mon Sep 09 16:06:04 MDT 2019 by andrewstewart +\* Last modified Mon Sep 09 17:27:48 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 25839993f5dadeda77b5fd28a20e5cc22b6bc7d5 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Mon, 9 Sep 2019 19:02:13 -0600 Subject: [PATCH 42/66] Eve only responds when challenge is ongoing --- ForceMove/ForceMove.tla | 149 ++++++++++++++++++---------------------- 1 file changed, 68 insertions(+), 81 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index fa84569..35e0f75 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -81,8 +81,6 @@ if /\ challengeOngoing /\ validTransition(commitment) then clearChallenge(commitment.turnNumber); -else - assert FALSE; end if; end macro; @@ -155,7 +153,7 @@ begin (***************************************************************************) AliceMoves: while AliceCanTakeAction -do +do AliceTakesAction: if /\ submittedTX = NULL /\ challengeOngoing @@ -209,17 +207,14 @@ begin (* challenge to expire. *) (***************************************************************************) EveMoves: -while EveCanTakeAction do - either ForceMove: +while EveCanTakeAction do EveTakesAction: + either with n \in NumParticipants..LatestTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } do forceMove([ turnNumber |-> n, signer |-> idx ]); end with; - or Respond: - if - /\ challengeOngoing - /\ ~AlicesMove(channel.challenge.turnNumber+1) + or if challengeOngoing then with turnNumber = channel.challenge.turnNumber + 1, commitment = [ turnNumber |-> turnNumber, signer |-> ParticipantIDX(turnNumber)] @@ -292,18 +287,16 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" THEN /\ IF /\ challengeOngoing /\ validTransition((submittedTX.commitment)) THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, - "Failure of assertion at line 70, column 1 of macro called at line 137, column 58.") + "Failure of assertion at line 70, column 1 of macro called at line 134, column 58.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], challenge |-> NULL ] - ELSE /\ PrintT((<<(submittedTX.commitment), channel.challenge>>)) - /\ Assert(FALSE, - "Failure of assertion at line 86, column 5 of macro called at line 137, column 58.") + ELSE /\ TRUE /\ UNCHANGED channel ELSE /\ Assert(FALSE, - "Failure of assertion at line 138, column 14.") + "Failure of assertion at line 135, column 14.") /\ UNCHANGED channel /\ submittedTX' = NULL ELSE /\ TRUE @@ -316,77 +309,72 @@ adjudicator == Adjudicator AliceMoves == /\ pc[Alice] = "AliceMoves" /\ IF AliceCanTakeAction - THEN /\ IF /\ submittedTX = NULL - /\ challengeOngoing - THEN /\ IF /\ channel.challenge.turnNumber < StartingTurnNumber - /\ submittedTX = NULL - THEN /\ LET turnNumber == CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer IN - submittedTX' = [ type |-> TX_Type.REFUTE, turnNumber |-> turnNumber] - /\ UNCHANGED channel - ELSE /\ IF /\ channel.challenge.turnNumber >= StartingTurnNumber - /\ AlicesMove(channel.challenge.turnNumber+1) - THEN /\ LET commitment == [ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ] IN - submittedTX' = [ type |-> TX_Type.RESPOND, commitment |-> commitment ] - /\ UNCHANGED channel - ELSE /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel - /\ UNCHANGED submittedTX - ELSE /\ IF /\ submittedTX = NULL - /\ ~challengeOngoing - THEN /\ submittedTX' = [ - commitment |-> [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ], - type |-> TX_Type.FORCE_MOVE - ] - ELSE /\ TRUE - /\ UNCHANGED submittedTX - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + THEN /\ pc' = [pc EXCEPT ![Alice] = "AliceTakesAction"] ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] - /\ UNCHANGED << channel, submittedTX >> - -alice == AliceMoves + /\ UNCHANGED << channel, submittedTX >> + +AliceTakesAction == /\ pc[Alice] = "AliceTakesAction" + /\ IF /\ submittedTX = NULL + /\ challengeOngoing + THEN /\ IF /\ channel.challenge.turnNumber < StartingTurnNumber + /\ submittedTX = NULL + THEN /\ LET turnNumber == CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer IN + submittedTX' = [ type |-> TX_Type.REFUTE, turnNumber |-> turnNumber] + /\ UNCHANGED channel + ELSE /\ IF /\ channel.challenge.turnNumber >= StartingTurnNumber + /\ AlicesMove(channel.challenge.turnNumber+1) + THEN /\ LET commitment == [ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ] IN + submittedTX' = [ type |-> TX_Type.RESPOND, commitment |-> commitment ] + /\ UNCHANGED channel + ELSE /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel + /\ UNCHANGED submittedTX + ELSE /\ IF /\ submittedTX = NULL + /\ ~challengeOngoing + THEN /\ submittedTX' = [ + commitment |-> [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ], + type |-> TX_Type.FORCE_MOVE + ] + ELSE /\ TRUE + /\ UNCHANGED submittedTX + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + +alice == AliceMoves \/ AliceTakesAction EveMoves == /\ pc[Eve] = "EveMoves" /\ IF EveCanTakeAction - THEN /\ \/ /\ pc' = [pc EXCEPT ![Eve] = "ForceMove"] - \/ /\ pc' = [pc EXCEPT ![Eve] = "Respond"] + THEN /\ pc' = [pc EXCEPT ![Eve] = "EveTakesAction"] ELSE /\ pc' = [pc EXCEPT ![Eve] = "Done"] /\ UNCHANGED << channel, submittedTX >> -ForceMove == /\ pc[Eve] = "ForceMove" - /\ \E n \in NumParticipants..LatestTurnNumber: - \E idx \in ParticipantIDXs \ { AlicesIDX }: - IF /\ channelOpen - /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ])) - THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> ([ turnNumber |-> n, signer |-> idx ]) ] @@ channel - ELSE /\ TRUE - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] - /\ UNCHANGED submittedTX - -Respond == /\ pc[Eve] = "Respond" - /\ IF /\ challengeOngoing - /\ ~AlicesMove(channel.challenge.turnNumber+1) - THEN /\ LET turnNumber == channel.challenge.turnNumber + 1 IN - LET commitment == [ turnNumber |-> turnNumber, signer |-> ParticipantIDX(turnNumber)] IN - IF /\ challengeOngoing - /\ validTransition(commitment) - THEN /\ Assert((commitment.turnNumber) \in Nat, - "Failure of assertion at line 70, column 1 of macro called at line 227, column 12.") - /\ channel' = [ - mode |-> ChannelMode.OPEN, - turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], - challenge |-> NULL - ] - ELSE /\ PrintT((<>)) - /\ Assert(FALSE, - "Failure of assertion at line 86, column 5 of macro called at line 227, column 12.") - /\ UNCHANGED channel - ELSE /\ TRUE - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] - /\ UNCHANGED submittedTX - -eve == EveMoves \/ ForceMove \/ Respond +EveTakesAction == /\ pc[Eve] = "EveTakesAction" + /\ \/ /\ \E n \in NumParticipants..LatestTurnNumber: + \E idx \in ParticipantIDXs \ { AlicesIDX }: + IF /\ channelOpen + /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ])) + THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> ([ turnNumber |-> n, signer |-> idx ]) ] @@ channel + ELSE /\ TRUE + /\ UNCHANGED channel + \/ /\ IF challengeOngoing + THEN /\ LET turnNumber == channel.challenge.turnNumber + 1 IN + LET commitment == [ turnNumber |-> turnNumber, signer |-> ParticipantIDX(turnNumber)] IN + IF /\ challengeOngoing + /\ validTransition(commitment) + THEN /\ Assert((commitment.turnNumber) \in Nat, + "Failure of assertion at line 70, column 1 of macro called at line 221, column 12.") + /\ channel' = [ + mode |-> ChannelMode.OPEN, + turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], + challenge |-> NULL + ] + ELSE /\ TRUE + /\ UNCHANGED channel + ELSE /\ TRUE + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] + /\ UNCHANGED submittedTX + +eve == EveMoves \/ EveTakesAction (* Allow infinite stuttering to prevent deadlock on termination. *) Terminating == /\ \A self \in ProcSet: pc[self] = "Done" @@ -432,10 +420,9 @@ FinalizedWithLatestTurnNumber == <>[]( AliceDoesNotLoseFunds == \/ AliceCanProgressChannel - \/ FinalizedWithLatestTurnNumber - + \/ FinalizedWithLatestTurnNumber ============================================================================= \* Modification History -\* Last modified Mon Sep 09 17:27:48 MDT 2019 by andrewstewart +\* Last modified Mon Sep 09 19:01:11 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From a3690b54394d8e8eb9273f24c7d746a8f63b6449 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Mon, 9 Sep 2019 19:50:49 -0600 Subject: [PATCH 43/66] Add invariant to verify that Eve can grieve --- ForceMove/ForceMove.tla | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 35e0f75..6db7d81 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -31,7 +31,6 @@ AlicesCommitments == StartingTurnNumber..LatestTurnNumber ParticipantIDX(turnNumber) == 1 + ((turnNumber - 1) % NumParticipants) AlicesMove(turnNumber) == ParticipantIDX(turnNumber) = AlicesIDX - Maximum(a,b) == IF a > b THEN a ELSE b ASSUME @@ -44,7 +43,8 @@ ASSUME variables channel = [turnNumber |-> [p \in ParticipantIDXs |-> 0], mode |-> ChannelMode.OPEN, challenge |-> NULL ], - submittedTX = NULL + submittedTX = NULL, + numForces = 0 define challengeOngoing == channel.mode = ChannelMode.CHALLENGE @@ -115,6 +115,7 @@ if /\ progressesChannel(commitment) then channel := [ mode |-> ChannelMode.CHALLENGE, challenge |-> commitment ] @@ channel; +\* numForces := numForces + 1; end if; end macro; @@ -230,7 +231,7 @@ end algorithm; \* BEGIN TRANSLATION -VARIABLES channel, submittedTX, pc +VARIABLES channel, submittedTX, numForces, pc (* define statement *) challengeOngoing == channel.mode = ChannelMode.CHALLENGE @@ -251,13 +252,14 @@ Refutable(n) == TRUE /\ n > channel.challenge.turnNumber -vars == << channel, submittedTX, pc >> +vars == << channel, submittedTX, numForces, pc >> ProcSet == {"Adjudicator"} \cup {Alice} \cup {Eve} Init == (* Global variables *) /\ channel = [turnNumber |-> [p \in ParticipantIDXs |-> 0], mode |-> ChannelMode.OPEN, challenge |-> NULL ] /\ submittedTX = NULL + /\ numForces = 0 /\ pc = [self \in ProcSet |-> CASE self = "Adjudicator" -> "Adjudicator" [] self = Alice -> "AliceMoves" [] self = Eve -> "EveMoves"] @@ -287,7 +289,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" THEN /\ IF /\ challengeOngoing /\ validTransition((submittedTX.commitment)) THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, - "Failure of assertion at line 70, column 1 of macro called at line 134, column 58.") + "Failure of assertion at line 71, column 1 of macro called at line 136, column 58.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], @@ -296,7 +298,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" ELSE /\ TRUE /\ UNCHANGED channel ELSE /\ Assert(FALSE, - "Failure of assertion at line 135, column 14.") + "Failure of assertion at line 137, column 14.") /\ UNCHANGED channel /\ submittedTX' = NULL ELSE /\ TRUE @@ -304,6 +306,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" /\ pc' = [pc EXCEPT !["Adjudicator"] = "Adjudicator"] ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "Done"] /\ UNCHANGED << channel, submittedTX >> + /\ UNCHANGED numForces adjudicator == Adjudicator @@ -311,7 +314,7 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" /\ IF AliceCanTakeAction THEN /\ pc' = [pc EXCEPT ![Alice] = "AliceTakesAction"] ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] - /\ UNCHANGED << channel, submittedTX >> + /\ UNCHANGED << channel, submittedTX, numForces >> AliceTakesAction == /\ pc[Alice] = "AliceTakesAction" /\ IF /\ submittedTX = NULL @@ -338,6 +341,7 @@ AliceTakesAction == /\ pc[Alice] = "AliceTakesAction" /\ UNCHANGED submittedTX /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] + /\ UNCHANGED numForces alice == AliceMoves \/ AliceTakesAction @@ -345,7 +349,7 @@ EveMoves == /\ pc[Eve] = "EveMoves" /\ IF EveCanTakeAction THEN /\ pc' = [pc EXCEPT ![Eve] = "EveTakesAction"] ELSE /\ pc' = [pc EXCEPT ![Eve] = "Done"] - /\ UNCHANGED << channel, submittedTX >> + /\ UNCHANGED << channel, submittedTX, numForces >> EveTakesAction == /\ pc[Eve] = "EveTakesAction" /\ \/ /\ \E n \in NumParticipants..LatestTurnNumber: @@ -420,9 +424,14 @@ FinalizedWithLatestTurnNumber == <>[]( AliceDoesNotLoseFunds == \/ AliceCanProgressChannel - \/ FinalizedWithLatestTurnNumber + \/ FinalizedWithLatestTurnNumber + +\* By incrementing numForces in the forceMove macro, we can keep a count of how many forceMoves have been played. +\* Behaviours that violate this invariant are therefore behaviours where Eve is successfully grieving Alice. +\* It's useful to violate this invariant to be able to inspect such traces. +EveCanGrieveAlice == numForces < 5 ============================================================================= \* Modification History -\* Last modified Mon Sep 09 19:01:11 MDT 2019 by andrewstewart +\* Last modified Mon Sep 09 19:49:41 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From c53bbe90413a4b7b1265b8f819297e1ff38f51b7 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Mon, 9 Sep 2019 19:51:49 -0600 Subject: [PATCH 44/66] Eve can refute --- ForceMove/ForceMove.tla | 44 +++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 6db7d81..3d02454 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -216,10 +216,13 @@ while EveCanTakeAction do EveTakesAction: forceMove([ turnNumber |-> n, signer |-> idx ]); end with; or if challengeOngoing - then with + then either with turnNumber = channel.challenge.turnNumber + 1, commitment = [ turnNumber |-> turnNumber, signer |-> ParticipantIDX(turnNumber)] do respondWithMove(commitment); end with; + or with turnNumber \in 0..LatestTurnNumber \cup { n \in Nat : n > LatestTurnNumber /\ ~AlicesMove(n) } + do refute(turnNumber); end with; + end either; end if; \* or Refute: skip; end either; @@ -360,23 +363,34 @@ EveTakesAction == /\ pc[Eve] = "EveTakesAction" ELSE /\ TRUE /\ UNCHANGED channel \/ /\ IF challengeOngoing - THEN /\ LET turnNumber == channel.challenge.turnNumber + 1 IN - LET commitment == [ turnNumber |-> turnNumber, signer |-> ParticipantIDX(turnNumber)] IN - IF /\ challengeOngoing - /\ validTransition(commitment) - THEN /\ Assert((commitment.turnNumber) \in Nat, - "Failure of assertion at line 70, column 1 of macro called at line 221, column 12.") - /\ channel' = [ - mode |-> ChannelMode.OPEN, - turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], - challenge |-> NULL - ] - ELSE /\ TRUE - /\ UNCHANGED channel + THEN /\ \/ /\ LET turnNumber == channel.challenge.turnNumber + 1 IN + LET commitment == [ turnNumber |-> turnNumber, signer |-> ParticipantIDX(turnNumber)] IN + IF /\ challengeOngoing + /\ validTransition(commitment) + THEN /\ Assert((commitment.turnNumber) \in Nat, + "Failure of assertion at line 71, column 1 of macro called at line 223, column 12.") + /\ channel' = [ + mode |-> ChannelMode.OPEN, + turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], + challenge |-> NULL + ] + ELSE /\ TRUE + /\ UNCHANGED channel + \/ /\ \E turnNumber \in 0..LatestTurnNumber \cup { n \in Nat : n > LatestTurnNumber /\ ~AlicesMove(n) }: + IF /\ challengeOngoing + /\ turnNumber > channel.turnNumber[ParticipantIDX(turnNumber)] + THEN /\ channel' = [ + mode |-> ChannelMode.OPEN, + challenge |-> NULL, + turnNumber |-> [i \in {ParticipantIDX(turnNumber)} |-> turnNumber] @@ channel.turnNumber + + ] + ELSE /\ TRUE + /\ UNCHANGED channel ELSE /\ TRUE /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] - /\ UNCHANGED submittedTX + /\ UNCHANGED << submittedTX, numForces >> eve == EveMoves \/ EveTakesAction From 133d179aecf4b36a201500f4a30d1c663995fec5 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 11:28:52 -0600 Subject: [PATCH 45/66] Update comments --- ForceMove/ForceMove.tla | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 3d02454..55d626c 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -39,7 +39,16 @@ ASSUME /\ AlicesIDX \in ParticipantIDXs /\ ~AlicesMove(LatestTurnNumber + 1) -(* --algorithm submitForceMove +(* --algorithm forceMove + +(***************************************************************************) +(* Alice calls adjudicator functions by submitting a pending transaction *) +(* with the function type and arguments. The adjudicator processes this *) +(* transaction and modifies the channel state on her behalf. However, *) +(* when Eve calls functions, she directly modifies the channel state. *) +(* This emulates a reality where Eve can consistently front-run Alice's *) +(* transactions, when desired. *) +(***************************************************************************) variables channel = [turnNumber |-> [p \in ParticipantIDXs |-> 0], mode |-> ChannelMode.OPEN, challenge |-> NULL ], @@ -122,7 +131,7 @@ end macro; fair process adjudicator = "Adjudicator" begin (***************************************************************************) -(* This process records submitted channels. *) +(* This process records submitted transactions. *) (***************************************************************************) Adjudicator: while @@ -142,16 +151,16 @@ end process; fair process alice = Alice begin -(***************************************************************************) -(* Alice has commitments (n - numParticipants)..(n-1). She wants to end *) -(* up with commitments (n - numParticipants + 1)..n. *) -(* *) -(* She is allowed to: *) -(* - Call submitForceMove with any states that she currently has *) -(* - Call refute with any state that she has *) -(* - Call respondWithMove or respondWithMove whenever there's an active *) -(* challenge where it's her turn to move *) -(***************************************************************************) +(**************************************************************************** +Alice has commitments (n - numParticipants)..(n-1). She wants to end +up with commitments (n - numParticipants + 1)..n. + +She is allowed to: + - Call submitForceMove with any states that she currently has + - Call refute with any state that she has + - Call respondWithMove or respondWithMove whenever there's an active + challenge where it's her turn to move +****************************************************************************) AliceMoves: while AliceCanTakeAction do AliceTakesAction: From 1141296713e6d343efb31858d4256d56831059c6 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 11:29:21 -0600 Subject: [PATCH 46/66] Add property that verifies that Alice cannot directly submit transactions --- ForceMove/ForceMove.tla | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 55d626c..ef83f5d 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -187,7 +187,7 @@ do AliceTakesAction: end with; else \* Alice has run out of allowed actions, resulting in the channel being finalized - channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel; + channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel; end if; elsif /\ submittedTX = NULL @@ -301,7 +301,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" THEN /\ IF /\ challengeOngoing /\ validTransition((submittedTX.commitment)) THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, - "Failure of assertion at line 71, column 1 of macro called at line 136, column 58.") + "Failure of assertion at line 79, column 1 of macro called at line 144, column 58.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], @@ -310,7 +310,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" ELSE /\ TRUE /\ UNCHANGED channel ELSE /\ Assert(FALSE, - "Failure of assertion at line 137, column 14.") + "Failure of assertion at line 145, column 14.") /\ UNCHANGED channel /\ submittedTX' = NULL ELSE /\ TRUE @@ -377,7 +377,7 @@ EveTakesAction == /\ pc[Eve] = "EveTakesAction" IF /\ challengeOngoing /\ validTransition(commitment) THEN /\ Assert((commitment.turnNumber) \in Nat, - "Failure of assertion at line 71, column 1 of macro called at line 223, column 12.") + "Failure of assertion at line 79, column 1 of macro called at line 231, column 12.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], @@ -454,7 +454,17 @@ AliceDoesNotLoseFunds == \* It's useful to violate this invariant to be able to inspect such traces. EveCanGrieveAlice == numForces < 5 +\* We can verify that Alice can never directly modify the channel with this property, with +\* the exception that she can finalize the channel. +AliceMustSubmitTransactions == [][ + /\ pc[Alice] = "AliceTakesAction" + /\ pc'[Alice] = "AliceMoves" + => + \/ UNCHANGED channel + \/ channel'.mode = ChannelMode.FINALIZED +]_<> + ============================================================================= \* Modification History -\* Last modified Mon Sep 09 19:49:41 MDT 2019 by andrewstewart +\* Last modified Tue Sep 10 11:12:10 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 7f75b1b5cce2c80c36d05a6d6bd1f1eda75189db Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 11:56:48 -0600 Subject: [PATCH 47/66] Add EveCannotFrontRun property and clarify numForces variable --- ForceMove/ForceMove.tla | 48 +++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index ef83f5d..093f0bb 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -124,7 +124,14 @@ if /\ progressesChannel(commitment) then channel := [ mode |-> ChannelMode.CHALLENGE, challenge |-> commitment ] @@ channel; -\* numForces := numForces + 1; + + \* We can't specify any properties that require any memory of the + \* behaviour up to the certain point (ie. the behaviour has passed through state X seven times in a row) + \* we have to embed the "memory" of the behaviour in the state itself. + \* By incrementing the number of forceMoves that have been called, we + \* multiply the number of distinct states by a large amount, but we can specify properties like + \* "Eve has not submitted 5 force moves" + \* numForces := numForces + 1; end if; end macro; @@ -301,7 +308,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" THEN /\ IF /\ challengeOngoing /\ validTransition((submittedTX.commitment)) THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, - "Failure of assertion at line 79, column 1 of macro called at line 144, column 58.") + "Failure of assertion at line 79, column 1 of macro called at line 151, column 58.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], @@ -310,7 +317,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" ELSE /\ TRUE /\ UNCHANGED channel ELSE /\ Assert(FALSE, - "Failure of assertion at line 145, column 14.") + "Failure of assertion at line 152, column 14.") /\ UNCHANGED channel /\ submittedTX' = NULL ELSE /\ TRUE @@ -377,7 +384,7 @@ EveTakesAction == /\ pc[Eve] = "EveTakesAction" IF /\ challengeOngoing /\ validTransition(commitment) THEN /\ Assert((commitment.turnNumber) \in Nat, - "Failure of assertion at line 79, column 1 of macro called at line 231, column 12.") + "Failure of assertion at line 79, column 1 of macro called at line 238, column 12.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], @@ -448,12 +455,8 @@ FinalizedWithLatestTurnNumber == <>[]( AliceDoesNotLoseFunds == \/ AliceCanProgressChannel \/ FinalizedWithLatestTurnNumber - -\* By incrementing numForces in the forceMove macro, we can keep a count of how many forceMoves have been played. -\* Behaviours that violate this invariant are therefore behaviours where Eve is successfully grieving Alice. -\* It's useful to violate this invariant to be able to inspect such traces. -EveCanGrieveAlice == numForces < 5 - + + \* We can verify that Alice can never directly modify the channel with this property, with \* the exception that she can finalize the channel. AliceMustSubmitTransactions == [][ @@ -464,7 +467,30 @@ AliceMustSubmitTransactions == [][ \/ channel'.mode = ChannelMode.FINALIZED ]_<> +\* It's useful to specify the following invariants or properties, since we can +\* inspect the trace of behaviours that violate them to verify that the model +\* checker is working as intended. + +EveCanGrieveAlice == numForces < 5 + + +\* Behaviours that violate this property exhibit Eve's ability to front-run: +\* Alice always submits a transaction that would change the channel state, if +\* it took effect immediately. Therefore, if the channel state is not changed +\* when a pending transaction is processed, Eve must have called a function +\* already. +EveCannotFrontRun ==[][ + /\ submittedTX # NULL + /\ submittedTX' = NULL + => + \/ channel' # channel + \* By uncommenting the following line, one can inspect traces where Eve might + \* have front-run Alice multiple times +\* \/ numForces <= 3 +]_<> + + ============================================================================= \* Modification History -\* Last modified Tue Sep 10 11:12:10 MDT 2019 by andrewstewart +\* Last modified Tue Sep 10 11:46:03 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 1543e1d2bda18cdbcbd0a1fcdc2490bc5cc6f553 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 12:19:15 -0600 Subject: [PATCH 48/66] Clean up spec --- ForceMove/ForceMove.tla | 144 +++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 82 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 093f0bb..d0c7d65 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -22,16 +22,15 @@ TX_Type == [ ] Range(f) == { f[x] : x \in DOMAIN f } +Maximum(a,b) == IF a > b THEN a ELSE b LatestTurnNumber == StartingTurnNumber + NumParticipants - 1 AlicesGoalTurnNumber == LatestTurnNumber + 1 -Names == { Alice, Eve } -ParticipantIDXs == 1..NumParticipants AlicesCommitments == StartingTurnNumber..LatestTurnNumber +ParticipantIDXs == 1..NumParticipants ParticipantIDX(turnNumber) == 1 + ((turnNumber - 1) % NumParticipants) AlicesMove(turnNumber) == ParticipantIDX(turnNumber) = AlicesIDX -Maximum(a,b) == IF a > b THEN a ELSE b ASSUME /\ StartingTurnNumber \in Nat @@ -63,15 +62,9 @@ validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(commitment) == /\ commitment.turnNumber = channel.challenge.turnNumber + 1 /\ commitment.signer = ParticipantIDX(commitment.turnNumber) - -AliceCanTakeAction == +AlicesGoalUnmet == /\ channel.mode # ChannelMode.FINALIZED /\ channel.turnNumber[AlicesIDX] < AlicesGoalTurnNumber -EveCanTakeAction == AliceCanTakeAction - -Refutable(n) == TRUE - /\ n % NumParticipants = channel.challenge.signer % NumParticipants - /\ n > channel.challenge.turnNumber end define; macro clearChallenge(turnNumber) @@ -93,15 +86,6 @@ then clearChallenge(commitment.turnNumber); end if; end macro; -macro respondWithAlternativeMove(commitment) -begin -if - /\ challengeOngoing - /\ commitment.turnNumber > channel.challenge.turnNumber + 1 -then clearChallenge(commitment.turnNumber); -end if; -end macro; - macro refute(turnNumber) begin if @@ -112,7 +96,9 @@ channel := [ mode |-> ChannelMode.OPEN, challenge |-> NULL, turnNumber |-> [i \in {ParticipantIDX(turnNumber)} |-> turnNumber] @@ channel.turnNumber -\* turnNumber |-> channel.turnNumber \* With this effect, eve can infinitely grief + \* By switching to the following effect, we can see how Eve could infinitely grief + \* with the previous version of the force-move protocol. +\* turnNumber |-> channel.turnNumber ]; end if; end macro; @@ -141,10 +127,7 @@ begin (* This process records submitted transactions. *) (***************************************************************************) Adjudicator: -while - \/ AliceCanTakeAction - \/ EveCanTakeAction -do +while AlicesGoalUnmet do AdjudicatorProcesses: if submittedTX # NULL then if submittedTX.type = TX_Type.FORCE_MOVE then forceMove(submittedTX.commitment); elsif submittedTX.type = TX_Type.REFUTE then refute(submittedTX.turnNumber); @@ -169,8 +152,7 @@ She is allowed to: challenge where it's her turn to move ****************************************************************************) AliceMoves: -while AliceCanTakeAction -do AliceTakesAction: +while AlicesGoalUnmet do AliceTakesAction: if /\ submittedTX = NULL /\ challengeOngoing @@ -224,7 +206,7 @@ begin (* challenge to expire. *) (***************************************************************************) EveMoves: -while EveCanTakeAction do EveTakesAction: +while AlicesGoalUnmet do EveTakesAction: either with n \in NumParticipants..LatestTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } @@ -240,7 +222,6 @@ while EveCanTakeAction do EveTakesAction: do refute(turnNumber); end with; end either; end if; -\* or Refute: skip; end either; end while; end process; @@ -260,15 +241,9 @@ validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(commitment) == /\ commitment.turnNumber = channel.challenge.turnNumber + 1 /\ commitment.signer = ParticipantIDX(commitment.turnNumber) - -AliceCanTakeAction == +AlicesGoalUnmet == /\ channel.mode # ChannelMode.FINALIZED /\ channel.turnNumber[AlicesIDX] < AlicesGoalTurnNumber -EveCanTakeAction == AliceCanTakeAction - -Refutable(n) == TRUE - /\ n % NumParticipants = channel.challenge.signer % NumParticipants - /\ n > channel.challenge.turnNumber vars == << channel, submittedTX, numForces, pc >> @@ -284,53 +259,57 @@ Init == (* Global variables *) [] self = Eve -> "EveMoves"] Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" - /\ IF \/ AliceCanTakeAction - \/ EveCanTakeAction - THEN /\ IF submittedTX # NULL - THEN /\ IF submittedTX.type = TX_Type.FORCE_MOVE - THEN /\ IF /\ channelOpen - /\ progressesChannel((submittedTX.commitment)) - THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> (submittedTX.commitment) ] @@ channel - ELSE /\ TRUE - /\ UNCHANGED channel - ELSE /\ IF submittedTX.type = TX_Type.REFUTE - THEN /\ IF /\ challengeOngoing - /\ (submittedTX.turnNumber) > channel.turnNumber[ParticipantIDX((submittedTX.turnNumber))] - THEN /\ channel' = [ - mode |-> ChannelMode.OPEN, - challenge |-> NULL, - turnNumber |-> [i \in {ParticipantIDX((submittedTX.turnNumber))} |-> (submittedTX.turnNumber)] @@ channel.turnNumber - - ] - ELSE /\ TRUE - /\ UNCHANGED channel - ELSE /\ IF submittedTX.type = TX_Type.RESPOND - THEN /\ IF /\ challengeOngoing - /\ validTransition((submittedTX.commitment)) - THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, - "Failure of assertion at line 79, column 1 of macro called at line 151, column 58.") - /\ channel' = [ - mode |-> ChannelMode.OPEN, - turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], - challenge |-> NULL - ] - ELSE /\ TRUE - /\ UNCHANGED channel - ELSE /\ Assert(FALSE, - "Failure of assertion at line 152, column 14.") - /\ UNCHANGED channel - /\ submittedTX' = NULL - ELSE /\ TRUE - /\ UNCHANGED << channel, submittedTX >> - /\ pc' = [pc EXCEPT !["Adjudicator"] = "Adjudicator"] + /\ IF AlicesGoalUnmet + THEN /\ pc' = [pc EXCEPT !["Adjudicator"] = "AdjudicatorProcesses"] ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "Done"] - /\ UNCHANGED << channel, submittedTX >> - /\ UNCHANGED numForces + /\ UNCHANGED << channel, submittedTX, numForces >> + +AdjudicatorProcesses == /\ pc["Adjudicator"] = "AdjudicatorProcesses" + /\ IF submittedTX # NULL + THEN /\ IF submittedTX.type = TX_Type.FORCE_MOVE + THEN /\ IF /\ channelOpen + /\ progressesChannel((submittedTX.commitment)) + THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> (submittedTX.commitment) ] @@ channel + ELSE /\ TRUE + /\ UNCHANGED channel + ELSE /\ IF submittedTX.type = TX_Type.REFUTE + THEN /\ IF /\ challengeOngoing + /\ (submittedTX.turnNumber) > channel.turnNumber[ParticipantIDX((submittedTX.turnNumber))] + THEN /\ channel' = [ + mode |-> ChannelMode.OPEN, + challenge |-> NULL, + turnNumber |-> [i \in {ParticipantIDX((submittedTX.turnNumber))} |-> (submittedTX.turnNumber)] @@ channel.turnNumber + + + + ] + ELSE /\ TRUE + /\ UNCHANGED channel + ELSE /\ IF submittedTX.type = TX_Type.RESPOND + THEN /\ IF /\ challengeOngoing + /\ validTransition((submittedTX.commitment)) + THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, + "Failure of assertion at line 73, column 1 of macro called at line 135, column 58.") + /\ channel' = [ + mode |-> ChannelMode.OPEN, + turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], + challenge |-> NULL + ] + ELSE /\ TRUE + /\ UNCHANGED channel + ELSE /\ Assert(FALSE, + "Failure of assertion at line 136, column 14.") + /\ UNCHANGED channel + /\ submittedTX' = NULL + ELSE /\ TRUE + /\ UNCHANGED << channel, submittedTX >> + /\ pc' = [pc EXCEPT !["Adjudicator"] = "Adjudicator"] + /\ UNCHANGED numForces -adjudicator == Adjudicator +adjudicator == Adjudicator \/ AdjudicatorProcesses AliceMoves == /\ pc[Alice] = "AliceMoves" - /\ IF AliceCanTakeAction + /\ IF AlicesGoalUnmet THEN /\ pc' = [pc EXCEPT ![Alice] = "AliceTakesAction"] ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] /\ UNCHANGED << channel, submittedTX, numForces >> @@ -365,7 +344,7 @@ AliceTakesAction == /\ pc[Alice] = "AliceTakesAction" alice == AliceMoves \/ AliceTakesAction EveMoves == /\ pc[Eve] = "EveMoves" - /\ IF EveCanTakeAction + /\ IF AlicesGoalUnmet THEN /\ pc' = [pc EXCEPT ![Eve] = "EveTakesAction"] ELSE /\ pc' = [pc EXCEPT ![Eve] = "Done"] /\ UNCHANGED << channel, submittedTX, numForces >> @@ -384,7 +363,7 @@ EveTakesAction == /\ pc[Eve] = "EveTakesAction" IF /\ challengeOngoing /\ validTransition(commitment) THEN /\ Assert((commitment.turnNumber) \in Nat, - "Failure of assertion at line 79, column 1 of macro called at line 238, column 12.") + "Failure of assertion at line 73, column 1 of macro called at line 221, column 12.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], @@ -400,6 +379,8 @@ EveTakesAction == /\ pc[Eve] = "EveTakesAction" challenge |-> NULL, turnNumber |-> [i \in {ParticipantIDX(turnNumber)} |-> turnNumber] @@ channel.turnNumber + + ] ELSE /\ TRUE /\ UNCHANGED channel @@ -473,7 +454,6 @@ AliceMustSubmitTransactions == [][ EveCanGrieveAlice == numForces < 5 - \* Behaviours that violate this property exhibit Eve's ability to front-run: \* Alice always submits a transaction that would change the channel state, if \* it took effect immediately. Therefore, if the channel state is not changed @@ -492,5 +472,5 @@ EveCannotFrontRun ==[][ ============================================================================= \* Modification History -\* Last modified Tue Sep 10 11:46:03 MDT 2019 by andrewstewart +\* Last modified Tue Sep 10 12:06:45 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 4139c89d726d497d1e818cd29b340908653d97ee Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 12:24:50 -0600 Subject: [PATCH 49/66] Refute checks that the challenge signer signed the state submitted --- ForceMove/ForceMove.tla | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index d0c7d65..84ce58c 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -90,6 +90,7 @@ macro refute(turnNumber) begin if /\ challengeOngoing + /\ ParticipantIDX(turnNumber) = channel.challenge.signer /\ turnNumber > channel.turnNumber[ParticipantIDX(turnNumber)] then channel := [ @@ -274,6 +275,7 @@ AdjudicatorProcesses == /\ pc["Adjudicator"] = "AdjudicatorProcesses" /\ UNCHANGED channel ELSE /\ IF submittedTX.type = TX_Type.REFUTE THEN /\ IF /\ challengeOngoing + /\ ParticipantIDX((submittedTX.turnNumber)) = channel.challenge.signer /\ (submittedTX.turnNumber) > channel.turnNumber[ParticipantIDX((submittedTX.turnNumber))] THEN /\ channel' = [ mode |-> ChannelMode.OPEN, @@ -289,7 +291,7 @@ AdjudicatorProcesses == /\ pc["Adjudicator"] = "AdjudicatorProcesses" THEN /\ IF /\ challengeOngoing /\ validTransition((submittedTX.commitment)) THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, - "Failure of assertion at line 73, column 1 of macro called at line 135, column 58.") + "Failure of assertion at line 72, column 1 of macro called at line 135, column 58.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], @@ -363,7 +365,7 @@ EveTakesAction == /\ pc[Eve] = "EveTakesAction" IF /\ challengeOngoing /\ validTransition(commitment) THEN /\ Assert((commitment.turnNumber) \in Nat, - "Failure of assertion at line 73, column 1 of macro called at line 221, column 12.") + "Failure of assertion at line 72, column 1 of macro called at line 221, column 12.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], @@ -373,6 +375,7 @@ EveTakesAction == /\ pc[Eve] = "EveTakesAction" /\ UNCHANGED channel \/ /\ \E turnNumber \in 0..LatestTurnNumber \cup { n \in Nat : n > LatestTurnNumber /\ ~AlicesMove(n) }: IF /\ challengeOngoing + /\ ParticipantIDX(turnNumber) = channel.challenge.signer /\ turnNumber > channel.turnNumber[ParticipantIDX(turnNumber)] THEN /\ channel' = [ mode |-> ChannelMode.OPEN, @@ -472,5 +475,5 @@ EveCannotFrontRun ==[][ ============================================================================= \* Modification History -\* Last modified Tue Sep 10 12:06:45 MDT 2019 by andrewstewart +\* Last modified Tue Sep 10 12:22:32 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From bc3c1693fbad88e13cc7530f6f7cd390704555b3 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 12:29:47 -0600 Subject: [PATCH 50/66] Clarify Eve's refute ability --- ForceMove/ForceMove.tla | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 84ce58c..8054a5e 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -166,15 +166,13 @@ while AlicesGoalUnmet do AliceTakesAction: \* She can therefore call refute with exactly one commitment, according to \* the channel's current turnNumber. with turnNumber = CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer - do submittedTX := [ type |-> TX_Type.REFUTE, turnNumber |-> turnNumber]; - end with; + do submittedTX := [ type |-> TX_Type.REFUTE, turnNumber |-> turnNumber]; end with; elsif /\ channel.challenge.turnNumber >= StartingTurnNumber /\ AlicesMove(channel.challenge.turnNumber+1) then with commitment = [ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ] - do submittedTX := [ type |-> TX_Type.RESPOND, commitment |-> commitment ]; - end with; + do submittedTX := [ type |-> TX_Type.RESPOND, commitment |-> commitment ]; end with; else \* Alice has run out of allowed actions, resulting in the channel being finalized channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel; @@ -219,7 +217,13 @@ while AlicesGoalUnmet do EveTakesAction: turnNumber = channel.challenge.turnNumber + 1, commitment = [ turnNumber |-> turnNumber, signer |-> ParticipantIDX(turnNumber)] do respondWithMove(commitment); end with; - or with turnNumber \in 0..LatestTurnNumber \cup { n \in Nat : n > LatestTurnNumber /\ ~AlicesMove(n) } + or with turnNumber \in {} + \* Eve can refute with any state she has. Alice has seen all of these states. + \cup 0..LatestTurnNumber + \* Since Eve can sign arbitrary data with any private key other than Alice's, + \* she can also refute with arbitrarily states, as long as it's not Alice's + \* turn in that state. + \cup { n \in Nat : ~AlicesMove(n) } do refute(turnNumber); end with; end either; end if; @@ -365,7 +369,7 @@ EveTakesAction == /\ pc[Eve] = "EveTakesAction" IF /\ challengeOngoing /\ validTransition(commitment) THEN /\ Assert((commitment.turnNumber) \in Nat, - "Failure of assertion at line 72, column 1 of macro called at line 221, column 12.") + "Failure of assertion at line 72, column 1 of macro called at line 219, column 12.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], @@ -373,7 +377,13 @@ EveTakesAction == /\ pc[Eve] = "EveTakesAction" ] ELSE /\ TRUE /\ UNCHANGED channel - \/ /\ \E turnNumber \in 0..LatestTurnNumber \cup { n \in Nat : n > LatestTurnNumber /\ ~AlicesMove(n) }: + \/ /\ \E turnNumber \in {} + + \cup 0..LatestTurnNumber + + + + \cup { n \in Nat : ~AlicesMove(n) }: IF /\ challengeOngoing /\ ParticipantIDX(turnNumber) = channel.challenge.signer /\ turnNumber > channel.turnNumber[ParticipantIDX(turnNumber)] @@ -475,5 +485,5 @@ EveCannotFrontRun ==[][ ============================================================================= \* Modification History -\* Last modified Tue Sep 10 12:22:32 MDT 2019 by andrewstewart +\* Last modified Tue Sep 10 12:29:00 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From eb8f0b07168f9bae8d705ea4639bcfec07b4aa49 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 12:31:04 -0600 Subject: [PATCH 51/66] Eve can sleep --- ForceMove/ForceMove.tla | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 8054a5e..fcbc09f 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -227,6 +227,7 @@ while AlicesGoalUnmet do EveTakesAction: do refute(turnNumber); end with; end either; end if; + or skip; \* Eve goes offline end either; end while; end process; @@ -399,6 +400,8 @@ EveTakesAction == /\ pc[Eve] = "EveTakesAction" /\ UNCHANGED channel ELSE /\ TRUE /\ UNCHANGED channel + \/ /\ TRUE + /\ UNCHANGED channel /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] /\ UNCHANGED << submittedTX, numForces >> @@ -485,5 +488,5 @@ EveCannotFrontRun ==[][ ============================================================================= \* Modification History -\* Last modified Tue Sep 10 12:29:00 MDT 2019 by andrewstewart +\* Last modified Tue Sep 10 12:30:23 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 66b387700acf3662776f45b69bfc6e5a366b5b45 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 16:04:06 -0600 Subject: [PATCH 52/66] Alice does not directly modify channel state --- ForceMove/ForceMove.tla | 84 +++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 37 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index fcbc09f..11a9ea7 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -18,7 +18,8 @@ ChannelMode == [ TX_Type == [ FORCE_MOVE |-> "FORCE_MOVE", REFUTE |-> "REFUTE", - RESPOND |-> "RESPOND" + RESPOND |-> "RESPOND", + TIMEOUT |-> "TIMEOUT" ] Range(f) == { f[x] : x \in DOMAIN f } @@ -92,6 +93,7 @@ if /\ challengeOngoing /\ ParticipantIDX(turnNumber) = channel.challenge.signer /\ turnNumber > channel.turnNumber[ParticipantIDX(turnNumber)] + /\ turnNumber > channel.challenge.turnNumber then channel := [ mode |-> ChannelMode.OPEN, @@ -122,17 +124,28 @@ then end if; end macro; +macro timeout() +begin +if challengeOngoing then +channel := [ + mode |-> ChannelMode.FINALIZED, + turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] +] @@ channel; +end if; +end macro; + fair process adjudicator = "Adjudicator" begin (***************************************************************************) (* This process records submitted transactions. *) (***************************************************************************) Adjudicator: -while AlicesGoalUnmet do AdjudicatorProcesses: +while AlicesGoalUnmet \/ submittedTX # NULL do AdjudicatorProcesses: if submittedTX # NULL then if submittedTX.type = TX_Type.FORCE_MOVE then forceMove(submittedTX.commitment); elsif submittedTX.type = TX_Type.REFUTE then refute(submittedTX.turnNumber); elsif submittedTX.type = TX_Type.RESPOND then respondWithMove(submittedTX.commitment); + elsif submittedTX.type = TX_Type.TIMEOUT then timeout(); else assert FALSE; end if; submittedTX := NULL; @@ -154,9 +167,8 @@ She is allowed to: ****************************************************************************) AliceMoves: while AlicesGoalUnmet do AliceTakesAction: - if - /\ submittedTX = NULL - /\ challengeOngoing + await submittedTX = NULL; + if challengeOngoing then if /\ channel.challenge.turnNumber < StartingTurnNumber @@ -174,13 +186,10 @@ while AlicesGoalUnmet do AliceTakesAction: with commitment = [ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ] do submittedTX := [ type |-> TX_Type.RESPOND, commitment |-> commitment ]; end with; else - \* Alice has run out of allowed actions, resulting in the channel being finalized - channel := [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel; + \* Alice has run out of allowed actions. + submittedTX := [ type |-> TX_Type.TIMEOUT ]; end if; - elsif - /\ submittedTX = NULL - /\ ~challengeOngoing - then + else submittedTX := [ commitment |-> [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ], type |-> TX_Type.FORCE_MOVE @@ -265,7 +274,7 @@ Init == (* Global variables *) [] self = Eve -> "EveMoves"] Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" - /\ IF AlicesGoalUnmet + /\ IF AlicesGoalUnmet \/ submittedTX # NULL THEN /\ pc' = [pc EXCEPT !["Adjudicator"] = "AdjudicatorProcesses"] ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "Done"] /\ UNCHANGED << channel, submittedTX, numForces >> @@ -282,6 +291,7 @@ AdjudicatorProcesses == /\ pc["Adjudicator"] = "AdjudicatorProcesses" THEN /\ IF /\ challengeOngoing /\ ParticipantIDX((submittedTX.turnNumber)) = channel.challenge.signer /\ (submittedTX.turnNumber) > channel.turnNumber[ParticipantIDX((submittedTX.turnNumber))] + /\ (submittedTX.turnNumber) > channel.challenge.turnNumber THEN /\ channel' = [ mode |-> ChannelMode.OPEN, challenge |-> NULL, @@ -296,7 +306,7 @@ AdjudicatorProcesses == /\ pc["Adjudicator"] = "AdjudicatorProcesses" THEN /\ IF /\ challengeOngoing /\ validTransition((submittedTX.commitment)) THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, - "Failure of assertion at line 72, column 1 of macro called at line 135, column 58.") + "Failure of assertion at line 73, column 1 of macro called at line 147, column 58.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], @@ -304,9 +314,17 @@ AdjudicatorProcesses == /\ pc["Adjudicator"] = "AdjudicatorProcesses" ] ELSE /\ TRUE /\ UNCHANGED channel - ELSE /\ Assert(FALSE, - "Failure of assertion at line 136, column 14.") - /\ UNCHANGED channel + ELSE /\ IF submittedTX.type = TX_Type.TIMEOUT + THEN /\ IF challengeOngoing + THEN /\ channel' = [ + mode |-> ChannelMode.FINALIZED, + turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] + ] @@ channel + ELSE /\ TRUE + /\ UNCHANGED channel + ELSE /\ Assert(FALSE, + "Failure of assertion at line 149, column 14.") + /\ UNCHANGED channel /\ submittedTX' = NULL ELSE /\ TRUE /\ UNCHANGED << channel, submittedTX >> @@ -322,31 +340,23 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" /\ UNCHANGED << channel, submittedTX, numForces >> AliceTakesAction == /\ pc[Alice] = "AliceTakesAction" - /\ IF /\ submittedTX = NULL - /\ challengeOngoing + /\ submittedTX = NULL + /\ IF challengeOngoing THEN /\ IF /\ channel.challenge.turnNumber < StartingTurnNumber /\ submittedTX = NULL THEN /\ LET turnNumber == CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer IN submittedTX' = [ type |-> TX_Type.REFUTE, turnNumber |-> turnNumber] - /\ UNCHANGED channel ELSE /\ IF /\ channel.challenge.turnNumber >= StartingTurnNumber /\ AlicesMove(channel.challenge.turnNumber+1) THEN /\ LET commitment == [ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ] IN submittedTX' = [ type |-> TX_Type.RESPOND, commitment |-> commitment ] - /\ UNCHANGED channel - ELSE /\ channel' = [ mode |-> ChannelMode.FINALIZED, turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] ] @@ channel - /\ UNCHANGED submittedTX - ELSE /\ IF /\ submittedTX = NULL - /\ ~challengeOngoing - THEN /\ submittedTX' = [ - commitment |-> [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ], - type |-> TX_Type.FORCE_MOVE - ] - ELSE /\ TRUE - /\ UNCHANGED submittedTX - /\ UNCHANGED channel + ELSE /\ submittedTX' = [ type |-> TX_Type.TIMEOUT ] + ELSE /\ submittedTX' = [ + commitment |-> [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ], + type |-> TX_Type.FORCE_MOVE + ] /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED numForces + /\ UNCHANGED << channel, numForces >> alice == AliceMoves \/ AliceTakesAction @@ -370,7 +380,7 @@ EveTakesAction == /\ pc[Eve] = "EveTakesAction" IF /\ challengeOngoing /\ validTransition(commitment) THEN /\ Assert((commitment.turnNumber) \in Nat, - "Failure of assertion at line 72, column 1 of macro called at line 219, column 12.") + "Failure of assertion at line 73, column 1 of macro called at line 228, column 12.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], @@ -388,6 +398,7 @@ EveTakesAction == /\ pc[Eve] = "EveTakesAction" IF /\ challengeOngoing /\ ParticipantIDX(turnNumber) = channel.challenge.signer /\ turnNumber > channel.turnNumber[ParticipantIDX(turnNumber)] + /\ turnNumber > channel.challenge.turnNumber THEN /\ channel' = [ mode |-> ChannelMode.OPEN, challenge |-> NULL, @@ -429,6 +440,7 @@ AllowedCommitments == [ turnNumber: AllowedTurnNumbers, signer: ParticipantIDXs AllowedTransactions == { NULL } \cup [ type: { TX_Type.FORCE_MOVE, TX_Type.RESPOND }, commitment: AllowedCommitments ] \cup [ type: { TX_Type.REFUTE }, turnNumber: AllowedTurnNumbers ] + \cup [ type: { TX_Type.TIMEOUT } ] AllowedChannels == [ turnNumber: [ParticipantIDXs -> Nat] , mode: Range(ChannelMode), challenge: AllowedCommitments \cup { NULL } ] @@ -459,9 +471,7 @@ AliceDoesNotLoseFunds == AliceMustSubmitTransactions == [][ /\ pc[Alice] = "AliceTakesAction" /\ pc'[Alice] = "AliceMoves" - => - \/ UNCHANGED channel - \/ channel'.mode = ChannelMode.FINALIZED + => UNCHANGED channel ]_<> \* It's useful to specify the following invariants or properties, since we can @@ -488,5 +498,5 @@ EveCannotFrontRun ==[][ ============================================================================= \* Modification History -\* Last modified Tue Sep 10 12:30:23 MDT 2019 by andrewstewart +\* Last modified Tue Sep 10 16:04:23 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From f5bc0a90e54574304dc594e7d35050ae6f38482f Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 16:20:34 -0600 Subject: [PATCH 53/66] Remove timeout "transactions" --- ForceMove/ForceMove.tla | 60 +++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 11a9ea7..994df4e 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -18,8 +18,7 @@ ChannelMode == [ TX_Type == [ FORCE_MOVE |-> "FORCE_MOVE", REFUTE |-> "REFUTE", - RESPOND |-> "RESPOND", - TIMEOUT |-> "TIMEOUT" + RESPOND |-> "RESPOND" ] Range(f) == { f[x] : x \in DOMAIN f } @@ -145,7 +144,6 @@ while AlicesGoalUnmet \/ submittedTX # NULL do AdjudicatorProcesses: if submittedTX.type = TX_Type.FORCE_MOVE then forceMove(submittedTX.commitment); elsif submittedTX.type = TX_Type.REFUTE then refute(submittedTX.turnNumber); elsif submittedTX.type = TX_Type.RESPOND then respondWithMove(submittedTX.commitment); - elsif submittedTX.type = TX_Type.TIMEOUT then timeout(); else assert FALSE; end if; submittedTX := NULL; @@ -168,28 +166,23 @@ She is allowed to: AliceMoves: while AlicesGoalUnmet do AliceTakesAction: await submittedTX = NULL; - if challengeOngoing - then - if - /\ channel.challenge.turnNumber < StartingTurnNumber - /\ submittedTX = NULL - then + if challengeOngoing then with turnNumber = channel.challenge.turnNumber do + if turnNumber < StartingTurnNumber then \* Alice has signed commitments from StartingTurnNumber up to LastTurnNumber. \* She can therefore call refute with exactly one commitment, according to \* the channel's current turnNumber. - with turnNumber = CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer - do submittedTX := [ type |-> TX_Type.REFUTE, turnNumber |-> turnNumber]; end with; - elsif - /\ channel.challenge.turnNumber >= StartingTurnNumber - /\ AlicesMove(channel.challenge.turnNumber+1) - then - with commitment = [ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ] - do submittedTX := [ type |-> TX_Type.RESPOND, commitment |-> commitment ]; end with; - else - \* Alice has run out of allowed actions. - submittedTX := [ type |-> TX_Type.TIMEOUT ]; + with refutation = CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer + do submittedTX := [ type |-> TX_Type.REFUTE, turnNumber |-> refutation]; end with; + elsif turnNumber < LatestTurnNumber then + with response = turnNumber + 1, + commitment = [ turnNumber |-> response, signer |-> ParticipantIDX(response) ] + do + assert response \in AlicesCommitments; + submittedTX := [ type |-> TX_Type.RESPOND, commitment |-> commitment ]; + end with; + else skip; \* Alice has run out of allowed actions. end if; - else + end with; else submittedTX := [ commitment |-> [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ], type |-> TX_Type.FORCE_MOVE @@ -342,15 +335,18 @@ AliceMoves == /\ pc[Alice] = "AliceMoves" AliceTakesAction == /\ pc[Alice] = "AliceTakesAction" /\ submittedTX = NULL /\ IF challengeOngoing - THEN /\ IF /\ channel.challenge.turnNumber < StartingTurnNumber - /\ submittedTX = NULL - THEN /\ LET turnNumber == CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer IN - submittedTX' = [ type |-> TX_Type.REFUTE, turnNumber |-> turnNumber] - ELSE /\ IF /\ channel.challenge.turnNumber >= StartingTurnNumber - /\ AlicesMove(channel.challenge.turnNumber+1) - THEN /\ LET commitment == [ turnNumber |-> channel.challenge.turnNumber + 1, signer |-> AlicesIDX ] IN - submittedTX' = [ type |-> TX_Type.RESPOND, commitment |-> commitment ] - ELSE /\ submittedTX' = [ type |-> TX_Type.TIMEOUT ] + THEN /\ LET turnNumber == channel.challenge.turnNumber IN + IF turnNumber < StartingTurnNumber + THEN /\ LET refutation == CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer IN + submittedTX' = [ type |-> TX_Type.REFUTE, turnNumber |-> refutation] + ELSE /\ IF turnNumber < LatestTurnNumber + THEN /\ LET response == turnNumber + 1 IN + LET commitment == [ turnNumber |-> response, signer |-> ParticipantIDX(response) ] IN + /\ Assert(response \in AlicesCommitments, + "Failure of assertion at line 182, column 17.") + /\ submittedTX' = [ type |-> TX_Type.RESPOND, commitment |-> commitment ] + ELSE /\ TRUE + /\ UNCHANGED submittedTX ELSE /\ submittedTX' = [ commitment |-> [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ], type |-> TX_Type.FORCE_MOVE @@ -380,7 +376,7 @@ EveTakesAction == /\ pc[Eve] = "EveTakesAction" IF /\ challengeOngoing /\ validTransition(commitment) THEN /\ Assert((commitment.turnNumber) \in Nat, - "Failure of assertion at line 73, column 1 of macro called at line 228, column 12.") + "Failure of assertion at line 73, column 1 of macro called at line 223, column 12.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], @@ -498,5 +494,5 @@ EveCannotFrontRun ==[][ ============================================================================= \* Modification History -\* Last modified Tue Sep 10 16:04:23 MDT 2019 by andrewstewart +\* Last modified Tue Sep 10 16:18:03 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 216dd0c53dcc7af3f7d15ca763a49bbc25e44ec9 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 16:43:48 -0600 Subject: [PATCH 54/66] Remove FINALIZE mode Once the channel is in the CHALLENGE mode with the latest turn number, Eve would be forced to either - respond with a move (which Alice is ok with) - respond with an alternative move, providing a full round (which Alice has to be ok with, since she signed one of the commitments in that round, and has no control over the later commitments) - refute with a later state signed by Alice (which she can't) --- ForceMove/ForceMove.tla | 321 ++++++++++++++++++---------------------- 1 file changed, 140 insertions(+), 181 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 994df4e..8f480b8 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -10,8 +10,7 @@ CONSTANTS ChannelMode == [ OPEN |-> "OPEN", - CHALLENGE |-> "CHALLENGE", - FINALIZED |-> "FINALIZED" + CHALLENGE |-> "CHALLENGE" ] @@ -25,7 +24,6 @@ Range(f) == { f[x] : x \in DOMAIN f } Maximum(a,b) == IF a > b THEN a ELSE b LatestTurnNumber == StartingTurnNumber + NumParticipants - 1 -AlicesGoalTurnNumber == LatestTurnNumber + 1 AlicesCommitments == StartingTurnNumber..LatestTurnNumber ParticipantIDXs == 1..NumParticipants @@ -63,8 +61,8 @@ validTransition(commitment) == /\ commitment.turnNumber = channel.challenge.turnNumber + 1 /\ commitment.signer = ParticipantIDX(commitment.turnNumber) AlicesGoalUnmet == - /\ channel.mode # ChannelMode.FINALIZED - /\ channel.turnNumber[AlicesIDX] < AlicesGoalTurnNumber + \/ channel.mode = ChannelMode.OPEN + \/ channel.challenge.turnNumber # LatestTurnNumber end define; macro clearChallenge(turnNumber) @@ -119,17 +117,7 @@ then \* By incrementing the number of forceMoves that have been called, we \* multiply the number of distinct states by a large amount, but we can specify properties like \* "Eve has not submitted 5 force moves" - \* numForces := numForces + 1; -end if; -end macro; - -macro timeout() -begin -if challengeOngoing then -channel := [ - mode |-> ChannelMode.FINALIZED, - turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] -] @@ channel; +\* numForces := numForces + 1; end if; end macro; @@ -139,7 +127,7 @@ begin (* This process records submitted transactions. *) (***************************************************************************) Adjudicator: -while AlicesGoalUnmet \/ submittedTX # NULL do AdjudicatorProcesses: +while AlicesGoalUnmet \/ submittedTX # NULL do if submittedTX # NULL then if submittedTX.type = TX_Type.FORCE_MOVE then forceMove(submittedTX.commitment); elsif submittedTX.type = TX_Type.REFUTE then refute(submittedTX.turnNumber); @@ -163,8 +151,8 @@ She is allowed to: - Call respondWithMove or respondWithMove whenever there's an active challenge where it's her turn to move ****************************************************************************) -AliceMoves: -while AlicesGoalUnmet do AliceTakesAction: +A: +while AlicesGoalUnmet do await submittedTX = NULL; if challengeOngoing then with turnNumber = channel.challenge.turnNumber do if turnNumber < StartingTurnNumber then @@ -206,8 +194,8 @@ begin (* - She can choose not to do anything, thus causing any active *) (* challenge to expire. *) (***************************************************************************) -EveMoves: -while AlicesGoalUnmet do EveTakesAction: +E: +while AlicesGoalUnmet do either with n \in NumParticipants..LatestTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } @@ -250,8 +238,8 @@ validTransition(commitment) == /\ commitment.turnNumber = channel.challenge.turnNumber + 1 /\ commitment.signer = ParticipantIDX(commitment.turnNumber) AlicesGoalUnmet == - /\ channel.mode # ChannelMode.FINALIZED - /\ channel.turnNumber[AlicesIDX] < AlicesGoalTurnNumber + \/ channel.mode = ChannelMode.OPEN + \/ channel.challenge.turnNumber # LatestTurnNumber vars == << channel, submittedTX, numForces, pc >> @@ -263,156 +251,139 @@ Init == (* Global variables *) /\ submittedTX = NULL /\ numForces = 0 /\ pc = [self \in ProcSet |-> CASE self = "Adjudicator" -> "Adjudicator" - [] self = Alice -> "AliceMoves" - [] self = Eve -> "EveMoves"] + [] self = Alice -> "A" + [] self = Eve -> "E"] Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" /\ IF AlicesGoalUnmet \/ submittedTX # NULL - THEN /\ pc' = [pc EXCEPT !["Adjudicator"] = "AdjudicatorProcesses"] + THEN /\ IF submittedTX # NULL + THEN /\ IF submittedTX.type = TX_Type.FORCE_MOVE + THEN /\ IF /\ channelOpen + /\ progressesChannel((submittedTX.commitment)) + THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> (submittedTX.commitment) ] @@ channel + ELSE /\ TRUE + /\ UNCHANGED channel + ELSE /\ IF submittedTX.type = TX_Type.REFUTE + THEN /\ IF /\ challengeOngoing + /\ ParticipantIDX((submittedTX.turnNumber)) = channel.challenge.signer + /\ (submittedTX.turnNumber) > channel.turnNumber[ParticipantIDX((submittedTX.turnNumber))] + /\ (submittedTX.turnNumber) > channel.challenge.turnNumber + THEN /\ channel' = [ + mode |-> ChannelMode.OPEN, + challenge |-> NULL, + turnNumber |-> [i \in {ParticipantIDX((submittedTX.turnNumber))} |-> (submittedTX.turnNumber)] @@ channel.turnNumber + + + + ] + ELSE /\ TRUE + /\ UNCHANGED channel + ELSE /\ IF submittedTX.type = TX_Type.RESPOND + THEN /\ IF /\ challengeOngoing + /\ validTransition((submittedTX.commitment)) + THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, + "Failure of assertion at line 70, column 1 of macro called at line 134, column 58.") + /\ channel' = [ + mode |-> ChannelMode.OPEN, + turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], + challenge |-> NULL + ] + ELSE /\ TRUE + /\ UNCHANGED channel + ELSE /\ Assert(FALSE, + "Failure of assertion at line 135, column 14.") + /\ UNCHANGED channel + /\ submittedTX' = NULL + ELSE /\ TRUE + /\ UNCHANGED << channel, submittedTX >> + /\ pc' = [pc EXCEPT !["Adjudicator"] = "Adjudicator"] ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "Done"] - /\ UNCHANGED << channel, submittedTX, numForces >> - -AdjudicatorProcesses == /\ pc["Adjudicator"] = "AdjudicatorProcesses" - /\ IF submittedTX # NULL - THEN /\ IF submittedTX.type = TX_Type.FORCE_MOVE - THEN /\ IF /\ channelOpen - /\ progressesChannel((submittedTX.commitment)) - THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> (submittedTX.commitment) ] @@ channel - ELSE /\ TRUE - /\ UNCHANGED channel - ELSE /\ IF submittedTX.type = TX_Type.REFUTE - THEN /\ IF /\ challengeOngoing - /\ ParticipantIDX((submittedTX.turnNumber)) = channel.challenge.signer - /\ (submittedTX.turnNumber) > channel.turnNumber[ParticipantIDX((submittedTX.turnNumber))] - /\ (submittedTX.turnNumber) > channel.challenge.turnNumber - THEN /\ channel' = [ - mode |-> ChannelMode.OPEN, - challenge |-> NULL, - turnNumber |-> [i \in {ParticipantIDX((submittedTX.turnNumber))} |-> (submittedTX.turnNumber)] @@ channel.turnNumber - - - - ] - ELSE /\ TRUE - /\ UNCHANGED channel - ELSE /\ IF submittedTX.type = TX_Type.RESPOND - THEN /\ IF /\ challengeOngoing - /\ validTransition((submittedTX.commitment)) - THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, - "Failure of assertion at line 73, column 1 of macro called at line 147, column 58.") - /\ channel' = [ - mode |-> ChannelMode.OPEN, - turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], - challenge |-> NULL - ] - ELSE /\ TRUE - /\ UNCHANGED channel - ELSE /\ IF submittedTX.type = TX_Type.TIMEOUT - THEN /\ IF challengeOngoing - THEN /\ channel' = [ - mode |-> ChannelMode.FINALIZED, - turnNumber |-> [p \in ParticipantIDXs |-> channel.challenge.turnNumber] - ] @@ channel - ELSE /\ TRUE - /\ UNCHANGED channel - ELSE /\ Assert(FALSE, - "Failure of assertion at line 149, column 14.") - /\ UNCHANGED channel - /\ submittedTX' = NULL - ELSE /\ TRUE - /\ UNCHANGED << channel, submittedTX >> - /\ pc' = [pc EXCEPT !["Adjudicator"] = "Adjudicator"] - /\ UNCHANGED numForces - -adjudicator == Adjudicator \/ AdjudicatorProcesses - -AliceMoves == /\ pc[Alice] = "AliceMoves" - /\ IF AlicesGoalUnmet - THEN /\ pc' = [pc EXCEPT ![Alice] = "AliceTakesAction"] - ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] - /\ UNCHANGED << channel, submittedTX, numForces >> - -AliceTakesAction == /\ pc[Alice] = "AliceTakesAction" - /\ submittedTX = NULL - /\ IF challengeOngoing - THEN /\ LET turnNumber == channel.challenge.turnNumber IN - IF turnNumber < StartingTurnNumber - THEN /\ LET refutation == CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer IN - submittedTX' = [ type |-> TX_Type.REFUTE, turnNumber |-> refutation] - ELSE /\ IF turnNumber < LatestTurnNumber - THEN /\ LET response == turnNumber + 1 IN - LET commitment == [ turnNumber |-> response, signer |-> ParticipantIDX(response) ] IN - /\ Assert(response \in AlicesCommitments, - "Failure of assertion at line 182, column 17.") - /\ submittedTX' = [ type |-> TX_Type.RESPOND, commitment |-> commitment ] - ELSE /\ TRUE - /\ UNCHANGED submittedTX - ELSE /\ submittedTX' = [ - commitment |-> [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ], - type |-> TX_Type.FORCE_MOVE - ] - /\ pc' = [pc EXCEPT ![Alice] = "AliceMoves"] - /\ UNCHANGED << channel, numForces >> - -alice == AliceMoves \/ AliceTakesAction - -EveMoves == /\ pc[Eve] = "EveMoves" - /\ IF AlicesGoalUnmet - THEN /\ pc' = [pc EXCEPT ![Eve] = "EveTakesAction"] - ELSE /\ pc' = [pc EXCEPT ![Eve] = "Done"] - /\ UNCHANGED << channel, submittedTX, numForces >> - -EveTakesAction == /\ pc[Eve] = "EveTakesAction" - /\ \/ /\ \E n \in NumParticipants..LatestTurnNumber: - \E idx \in ParticipantIDXs \ { AlicesIDX }: - IF /\ channelOpen - /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ])) - THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> ([ turnNumber |-> n, signer |-> idx ]) ] @@ channel - ELSE /\ TRUE - /\ UNCHANGED channel - \/ /\ IF challengeOngoing - THEN /\ \/ /\ LET turnNumber == channel.challenge.turnNumber + 1 IN - LET commitment == [ turnNumber |-> turnNumber, signer |-> ParticipantIDX(turnNumber)] IN - IF /\ challengeOngoing - /\ validTransition(commitment) - THEN /\ Assert((commitment.turnNumber) \in Nat, - "Failure of assertion at line 73, column 1 of macro called at line 223, column 12.") - /\ channel' = [ - mode |-> ChannelMode.OPEN, - turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], - challenge |-> NULL - ] - ELSE /\ TRUE - /\ UNCHANGED channel - \/ /\ \E turnNumber \in {} - - \cup 0..LatestTurnNumber - - - - \cup { n \in Nat : ~AlicesMove(n) }: + /\ UNCHANGED << channel, submittedTX >> + /\ UNCHANGED numForces + +adjudicator == Adjudicator + +A == /\ pc[Alice] = "A" + /\ IF AlicesGoalUnmet + THEN /\ submittedTX = NULL + /\ IF challengeOngoing + THEN /\ LET turnNumber == channel.challenge.turnNumber IN + IF turnNumber < StartingTurnNumber + THEN /\ LET refutation == CHOOSE n \in AlicesCommitments : ParticipantIDX(n) = channel.challenge.signer IN + submittedTX' = [ type |-> TX_Type.REFUTE, turnNumber |-> refutation] + ELSE /\ IF turnNumber < LatestTurnNumber + THEN /\ LET response == turnNumber + 1 IN + LET commitment == [ turnNumber |-> response, signer |-> ParticipantIDX(response) ] IN + /\ Assert(response \in AlicesCommitments, + "Failure of assertion at line 168, column 17.") + /\ submittedTX' = [ type |-> TX_Type.RESPOND, commitment |-> commitment ] + ELSE /\ TRUE + /\ UNCHANGED submittedTX + ELSE /\ submittedTX' = [ + commitment |-> [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ], + type |-> TX_Type.FORCE_MOVE + ] + /\ pc' = [pc EXCEPT ![Alice] = "A"] + ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] + /\ UNCHANGED submittedTX + /\ UNCHANGED << channel, numForces >> + +alice == A + +E == /\ pc[Eve] = "E" + /\ IF AlicesGoalUnmet + THEN /\ \/ /\ \E n \in NumParticipants..LatestTurnNumber: + \E idx \in ParticipantIDXs \ { AlicesIDX }: + IF /\ channelOpen + /\ progressesChannel(([ turnNumber |-> n, signer |-> idx ])) + THEN /\ channel' = [ mode |-> ChannelMode.CHALLENGE, challenge |-> ([ turnNumber |-> n, signer |-> idx ]) ] @@ channel + ELSE /\ TRUE + /\ UNCHANGED channel + \/ /\ IF challengeOngoing + THEN /\ \/ /\ LET turnNumber == channel.challenge.turnNumber + 1 IN + LET commitment == [ turnNumber |-> turnNumber, signer |-> ParticipantIDX(turnNumber)] IN IF /\ challengeOngoing - /\ ParticipantIDX(turnNumber) = channel.challenge.signer - /\ turnNumber > channel.turnNumber[ParticipantIDX(turnNumber)] - /\ turnNumber > channel.challenge.turnNumber - THEN /\ channel' = [ + /\ validTransition(commitment) + THEN /\ Assert((commitment.turnNumber) \in Nat, + "Failure of assertion at line 70, column 1 of macro called at line 209, column 12.") + /\ channel' = [ mode |-> ChannelMode.OPEN, - challenge |-> NULL, - turnNumber |-> [i \in {ParticipantIDX(turnNumber)} |-> turnNumber] @@ channel.turnNumber - - - + turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], + challenge |-> NULL ] ELSE /\ TRUE /\ UNCHANGED channel - ELSE /\ TRUE - /\ UNCHANGED channel - \/ /\ TRUE - /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![Eve] = "EveMoves"] - /\ UNCHANGED << submittedTX, numForces >> - -eve == EveMoves \/ EveTakesAction + \/ /\ \E turnNumber \in {} + + \cup 0..LatestTurnNumber + + + + \cup { n \in Nat : ~AlicesMove(n) }: + IF /\ challengeOngoing + /\ ParticipantIDX(turnNumber) = channel.challenge.signer + /\ turnNumber > channel.turnNumber[ParticipantIDX(turnNumber)] + /\ turnNumber > channel.challenge.turnNumber + THEN /\ channel' = [ + mode |-> ChannelMode.OPEN, + challenge |-> NULL, + turnNumber |-> [i \in {ParticipantIDX(turnNumber)} |-> turnNumber] @@ channel.turnNumber + + + + ] + ELSE /\ TRUE + /\ UNCHANGED channel + ELSE /\ TRUE + /\ UNCHANGED channel + \/ /\ TRUE + /\ UNCHANGED channel + /\ pc' = [pc EXCEPT ![Eve] = "E"] + ELSE /\ pc' = [pc EXCEPT ![Eve] = "Done"] + /\ UNCHANGED channel + /\ UNCHANGED << submittedTX, numForces >> + +eve == E (* Allow infinite stuttering to prevent deadlock on termination. *) Terminating == /\ \A self \in ProcSet: pc[self] = "Done" @@ -436,31 +407,19 @@ AllowedCommitments == [ turnNumber: AllowedTurnNumbers, signer: ParticipantIDXs AllowedTransactions == { NULL } \cup [ type: { TX_Type.FORCE_MOVE, TX_Type.RESPOND }, commitment: AllowedCommitments ] \cup [ type: { TX_Type.REFUTE }, turnNumber: AllowedTurnNumbers ] - \cup [ type: { TX_Type.TIMEOUT } ] AllowedChannels == [ turnNumber: [ParticipantIDXs -> Nat] , mode: Range(ChannelMode), challenge: AllowedCommitments \cup { NULL } ] -\* Safety properties +\* Safety & liveness properties TypeOK == /\ channel \in AllowedChannels /\ submittedTX \in AllowedTransactions - -\* Liveness properties -AliceCanProgressChannel == <>[]( - /\ channel.mode = ChannelMode.OPEN - /\ channel.turnNumber[AlicesIDX] = AlicesGoalTurnNumber -) -FinalizedWithLatestTurnNumber == <>[]( - /\ channel.mode = ChannelMode.FINALIZED - /\ channel.turnNumber[AlicesIDX] = LatestTurnNumber +AliceCanProgressChannel == <>[]( + /\ channel.mode = ChannelMode.CHALLENGE + /\ channel.challenge.turnNumber = LatestTurnNumber ) - -AliceDoesNotLoseFunds == - \/ AliceCanProgressChannel - \/ FinalizedWithLatestTurnNumber - \* We can verify that Alice can never directly modify the channel with this property, with \* the exception that she can finalize the channel. @@ -494,5 +453,5 @@ EveCannotFrontRun ==[][ ============================================================================= \* Modification History -\* Last modified Tue Sep 10 16:18:03 MDT 2019 by andrewstewart +\* Last modified Tue Sep 10 16:58:25 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From f6e314c66fd64983e834f74af27ceefb0c8bf4e6 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 17:35:53 -0600 Subject: [PATCH 55/66] Remove unused model values --- ForceMove/ForceMove.tla | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 8f480b8..3e8b551 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -1,8 +1,6 @@ ----------------------------- MODULE ForceMove ----------------------------- EXTENDS Integers, Sequences, FiniteSets, TLC CONSTANTS - Alice, - Eve, StartingTurnNumber, NumParticipants, AlicesIDX, @@ -139,7 +137,7 @@ while AlicesGoalUnmet \/ submittedTX # NULL do end while; end process; -fair process alice = Alice +fair process alice = "Alice" begin (**************************************************************************** Alice has commitments (n - numParticipants)..(n-1). She wants to end @@ -179,7 +177,7 @@ while AlicesGoalUnmet do end while; end process; -fair process eve = Eve +fair process eve = "Eve" begin (***************************************************************************) (* Eve can do almost anything. *) @@ -244,15 +242,15 @@ AlicesGoalUnmet == vars == << channel, submittedTX, numForces, pc >> -ProcSet == {"Adjudicator"} \cup {Alice} \cup {Eve} +ProcSet == {"Adjudicator"} \cup {"Alice"} \cup {"Eve"} Init == (* Global variables *) /\ channel = [turnNumber |-> [p \in ParticipantIDXs |-> 0], mode |-> ChannelMode.OPEN, challenge |-> NULL ] /\ submittedTX = NULL /\ numForces = 0 /\ pc = [self \in ProcSet |-> CASE self = "Adjudicator" -> "Adjudicator" - [] self = Alice -> "A" - [] self = Eve -> "E"] + [] self = "Alice" -> "A" + [] self = "Eve" -> "E"] Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" /\ IF AlicesGoalUnmet \/ submittedTX # NULL @@ -282,7 +280,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" THEN /\ IF /\ challengeOngoing /\ validTransition((submittedTX.commitment)) THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, - "Failure of assertion at line 70, column 1 of macro called at line 134, column 58.") + "Failure of assertion at line 68, column 1 of macro called at line 132, column 58.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], @@ -291,7 +289,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" ELSE /\ TRUE /\ UNCHANGED channel ELSE /\ Assert(FALSE, - "Failure of assertion at line 135, column 14.") + "Failure of assertion at line 133, column 14.") /\ UNCHANGED channel /\ submittedTX' = NULL ELSE /\ TRUE @@ -303,7 +301,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" adjudicator == Adjudicator -A == /\ pc[Alice] = "A" +A == /\ pc["Alice"] = "A" /\ IF AlicesGoalUnmet THEN /\ submittedTX = NULL /\ IF challengeOngoing @@ -315,7 +313,7 @@ A == /\ pc[Alice] = "A" THEN /\ LET response == turnNumber + 1 IN LET commitment == [ turnNumber |-> response, signer |-> ParticipantIDX(response) ] IN /\ Assert(response \in AlicesCommitments, - "Failure of assertion at line 168, column 17.") + "Failure of assertion at line 166, column 17.") /\ submittedTX' = [ type |-> TX_Type.RESPOND, commitment |-> commitment ] ELSE /\ TRUE /\ UNCHANGED submittedTX @@ -323,14 +321,14 @@ A == /\ pc[Alice] = "A" commitment |-> [ turnNumber |-> LatestTurnNumber, signer |-> AlicesIDX ], type |-> TX_Type.FORCE_MOVE ] - /\ pc' = [pc EXCEPT ![Alice] = "A"] - ELSE /\ pc' = [pc EXCEPT ![Alice] = "Done"] + /\ pc' = [pc EXCEPT !["Alice"] = "A"] + ELSE /\ pc' = [pc EXCEPT !["Alice"] = "Done"] /\ UNCHANGED submittedTX /\ UNCHANGED << channel, numForces >> alice == A -E == /\ pc[Eve] = "E" +E == /\ pc["Eve"] = "E" /\ IF AlicesGoalUnmet THEN /\ \/ /\ \E n \in NumParticipants..LatestTurnNumber: \E idx \in ParticipantIDXs \ { AlicesIDX }: @@ -345,7 +343,7 @@ E == /\ pc[Eve] = "E" IF /\ challengeOngoing /\ validTransition(commitment) THEN /\ Assert((commitment.turnNumber) \in Nat, - "Failure of assertion at line 70, column 1 of macro called at line 209, column 12.") + "Failure of assertion at line 68, column 1 of macro called at line 207, column 12.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], @@ -378,8 +376,8 @@ E == /\ pc[Eve] = "E" /\ UNCHANGED channel \/ /\ TRUE /\ UNCHANGED channel - /\ pc' = [pc EXCEPT ![Eve] = "E"] - ELSE /\ pc' = [pc EXCEPT ![Eve] = "Done"] + /\ pc' = [pc EXCEPT !["Eve"] = "E"] + ELSE /\ pc' = [pc EXCEPT !["Eve"] = "Done"] /\ UNCHANGED channel /\ UNCHANGED << submittedTX, numForces >> @@ -424,8 +422,8 @@ AliceCanProgressChannel == <>[]( \* We can verify that Alice can never directly modify the channel with this property, with \* the exception that she can finalize the channel. AliceMustSubmitTransactions == [][ - /\ pc[Alice] = "AliceTakesAction" - /\ pc'[Alice] = "AliceMoves" + /\ pc["Alice"] = "AliceTakesAction" + /\ pc'["Alice"] = "AliceMoves" => UNCHANGED channel ]_<> @@ -453,5 +451,5 @@ EveCannotFrontRun ==[][ ============================================================================= \* Modification History -\* Last modified Tue Sep 10 16:58:25 MDT 2019 by andrewstewart +\* Last modified Tue Sep 10 17:35:35 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From b9933fece2cc599f49cdc637096437cc6b08678d Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 17:59:52 -0600 Subject: [PATCH 56/66] Add success configuration --- ForceMove/Success.cfg | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 ForceMove/Success.cfg diff --git a/ForceMove/Success.cfg b/ForceMove/Success.cfg new file mode 100644 index 0000000..c027863 --- /dev/null +++ b/ForceMove/Success.cfg @@ -0,0 +1,26 @@ +\* CONSTANT declarations +CONSTANT NULL = NULL +\* CONSTANT definitions +CONSTANT +StartingTurnNumber <- const_15681587964711770000 +\* CONSTANT definitions +CONSTANT +NumParticipants <- const_15681587964711771000 +\* CONSTANT definitions +CONSTANT +AlicesIDX <- const_15681587964711772000 +\* CONSTANT definition +CONSTANT +Nat <- def_ov_15681587964711773000 +\* SPECIFICATION definition +SPECIFICATION +Spec +\* INVARIANT definition +INVARIANT +TypeOK +\* PROPERTY definition +PROPERTY +Termination +AliceCanProgressChannel +AliceMustSubmitTransactions +\* Generated on Tue Sep 10 17:39:56 MDT 2019 \ No newline at end of file From b1fcaed94efd2fd6193d60c79f976720dc1af7ac Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 18:02:27 -0600 Subject: [PATCH 57/66] Add configuration to exhibit how Eve can front run Alice --- ForceMove/EveCannotFrontRun.cfg | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 ForceMove/EveCannotFrontRun.cfg diff --git a/ForceMove/EveCannotFrontRun.cfg b/ForceMove/EveCannotFrontRun.cfg new file mode 100644 index 0000000..e5b3934 --- /dev/null +++ b/ForceMove/EveCannotFrontRun.cfg @@ -0,0 +1,24 @@ +\* CONSTANT declarations +CONSTANT NULL = NULL +\* CONSTANT definitions +CONSTANT +StartingTurnNumber <- const_15681587964711770000 +\* CONSTANT definitions +CONSTANT +NumParticipants <- const_15681587964711771000 +\* CONSTANT definitions +CONSTANT +AlicesIDX <- const_15681587964711772000 +\* CONSTANT definition +CONSTANT +Nat <- def_ov_15681587964711773000 +\* SPECIFICATION definition +SPECIFICATION +Spec +\* INVARIANT definition +INVARIANT +TypeOK +\* PROPERTY definition +PROPERTY +EveCannotFrontRun +\* Generated on Tue Sep 10 17:39:56 MDT 2019 \ No newline at end of file From 4a8d45ef8b11679b4e6053ddf7cde675ccce09fe Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 18:04:04 -0600 Subject: [PATCH 58/66] Add some models --- ForceMove/ThreeParticipants.tla | 25 ++++++++++++++++++++++++ ForceMove/TwoParticipants.tla | 25 ++++++++++++++++++++++++ ForceMove/TwoParticipantsLongHistory.tla | 25 ++++++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 ForceMove/ThreeParticipants.tla create mode 100644 ForceMove/TwoParticipants.tla create mode 100644 ForceMove/TwoParticipantsLongHistory.tla diff --git a/ForceMove/ThreeParticipants.tla b/ForceMove/ThreeParticipants.tla new file mode 100644 index 0000000..2cf466b --- /dev/null +++ b/ForceMove/ThreeParticipants.tla @@ -0,0 +1,25 @@ +---- MODULE ThreeParticipants ---- +EXTENDS ForceMove, TLC + +\* CONSTANT definitions @modelParameterConstants:1StartingTurnNumber +const_15681587964711770000 == +5 +---- + +\* CONSTANT definitions @modelParameterConstants:2NumParticipants +const_15681587964711771000 == +3 +---- + +\* CONSTANT definitions @modelParameterConstants:3AlicesIDX +const_15681587964711772000 == +3 +---- + +\* CONSTANT definition @modelParameterDefinitions:0 +def_ov_15681587964711773000 == +0..20 +---- +============================================================================= +\* Modification History +\* Created Tue Sep 10 17:39:56 MDT 2019 by andrewstewart diff --git a/ForceMove/TwoParticipants.tla b/ForceMove/TwoParticipants.tla new file mode 100644 index 0000000..df7d717 --- /dev/null +++ b/ForceMove/TwoParticipants.tla @@ -0,0 +1,25 @@ +---- MODULE TwoParticipants ---- +EXTENDS ForceMove, TLC + +\* CONSTANT definitions @modelParameterConstants:1StartingTurnNumber +const_15681587964711770000 == +5 +---- + +\* CONSTANT definitions @modelParameterConstants:2NumParticipants +const_15681587964711771000 == +2 +---- + +\* CONSTANT definitions @modelParameterConstants:3AlicesIDX +const_15681587964711772000 == +2 +---- + +\* CONSTANT definition @modelParameterDefinitions:0 +def_ov_15681587964711773000 == +0..20 +---- +============================================================================= +\* Modification History +\* Created Tue Sep 10 17:39:56 MDT 2019 by andrewstewart diff --git a/ForceMove/TwoParticipantsLongHistory.tla b/ForceMove/TwoParticipantsLongHistory.tla new file mode 100644 index 0000000..6a7a0b9 --- /dev/null +++ b/ForceMove/TwoParticipantsLongHistory.tla @@ -0,0 +1,25 @@ +---- MODULE TwoParticipantsLongHistory ---- +EXTENDS ForceMove, TLC + +\* CONSTANT definitions @modelParameterConstants:1StartingTurnNumber +const_15681587964711770000 == +31 +---- + +\* CONSTANT definitions @modelParameterConstants:2NumParticipants +const_15681587964711771000 == +2 +---- + +\* CONSTANT definitions @modelParameterConstants:3AlicesIDX +const_15681587964711772000 == +2 +---- + +\* CONSTANT definition @modelParameterDefinitions:0 +def_ov_15681587964711773000 == +0..64 +---- +============================================================================= +\* Modification History +\* Created Tue Sep 10 17:39:56 MDT 2019 by andrewstewart From 8c42a5043d1de7622fe279dc8a540750b881c73b Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 18:34:29 -0600 Subject: [PATCH 59/66] Add explanation of the specification --- ForceMove/ForceMove.tla | 74 +++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 3e8b551..55b3e8c 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -11,7 +11,6 @@ ChannelMode == [ CHALLENGE |-> "CHALLENGE" ] - TX_Type == [ FORCE_MOVE |-> "FORCE_MOVE", REFUTE |-> "REFUTE", @@ -24,6 +23,45 @@ Maximum(a,b) == IF a > b THEN a ELSE b LatestTurnNumber == StartingTurnNumber + NumParticipants - 1 AlicesCommitments == StartingTurnNumber..LatestTurnNumber +(***************************************************************************) +(* The purpose of this specification is to outline an algorithm that *) +(* guarantees that a challenge is registered on chain with turnNumber *) +(* equal to LatestTurnNumber. It is guaranteed even with an antagonist *) +(* who can do anything (including front-run Alice an arbitrary number of *) +(* times) except *) +(* - signing data with Alice's private key *) +(* - corrupting the blockchain *) +(* *) +(* This guarantee has a key assumption, namely: *) +(* 1. When a challenge is recorded on the adjudicator, Alice is always *) +(* able to *) +(* a) notice the event *) +(* b) submit a transaction *) +(* c) receive confirmation that that transaction was mined *) +(* all before the challenge times out. *) +(* *) +(* If guarantee is met, then either *) +(* A. the channel concludes at this state; or *) +(* B. someone responds with a move that progresses the channel *) +(* C. someone responds with an alternative move that progresses the *) +(* channel *) +(* *) +(* Alice must accept A. She must also accept C -- indeed, she must accept *) +(* any alternative round that is recorded on chain, since she must have *) +(* signed exactly one state in that round, and has no control over what *) +(* the other participants does after that state. She would be most *) +(* satisfied with B. *) +(* *) +(* In reality, it is possible that Alice receives a state with turnNumber *) +(* LatestTurnNumber+1, and in this case Alice could (gracefully) abort her *) +(* algorithm and continue the channel. A future version of this *) +(* specification could consider this possibility. *) +(* *) +(* By inductively applying her algorithm, Alice can therefore guarantee *) +(* that either the channel progresses as long as she wishes, or it *) +(* concludes on the latest state that she has. *) +(***************************************************************************) + ParticipantIDXs == 1..NumParticipants ParticipantIDX(turnNumber) == 1 + ((turnNumber - 1) % NumParticipants) AlicesMove(turnNumber) == ParticipantIDX(turnNumber) = AlicesIDX @@ -58,9 +96,9 @@ validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(commitment) == /\ commitment.turnNumber = channel.challenge.turnNumber + 1 /\ commitment.signer = ParticipantIDX(commitment.turnNumber) -AlicesGoalUnmet == - \/ channel.mode = ChannelMode.OPEN - \/ channel.challenge.turnNumber # LatestTurnNumber +AlicesGoalMet == + /\ channel.mode = ChannelMode.CHALLENGE + /\ channel.challenge.turnNumber = LatestTurnNumber end define; macro clearChallenge(turnNumber) @@ -125,7 +163,7 @@ begin (* This process records submitted transactions. *) (***************************************************************************) Adjudicator: -while AlicesGoalUnmet \/ submittedTX # NULL do +while ~AlicesGoalMet \/ submittedTX # NULL do if submittedTX # NULL then if submittedTX.type = TX_Type.FORCE_MOVE then forceMove(submittedTX.commitment); elsif submittedTX.type = TX_Type.REFUTE then refute(submittedTX.turnNumber); @@ -150,7 +188,7 @@ She is allowed to: challenge where it's her turn to move ****************************************************************************) A: -while AlicesGoalUnmet do +while ~AlicesGoalMet do await submittedTX = NULL; if challengeOngoing then with turnNumber = channel.challenge.turnNumber do if turnNumber < StartingTurnNumber then @@ -193,7 +231,7 @@ begin (* challenge to expire. *) (***************************************************************************) E: -while AlicesGoalUnmet do +while ~AlicesGoalMet do either with n \in NumParticipants..LatestTurnNumber, idx \in ParticipantIDXs \ { AlicesIDX } @@ -235,9 +273,9 @@ validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(commitment) == /\ commitment.turnNumber = channel.challenge.turnNumber + 1 /\ commitment.signer = ParticipantIDX(commitment.turnNumber) -AlicesGoalUnmet == - \/ channel.mode = ChannelMode.OPEN - \/ channel.challenge.turnNumber # LatestTurnNumber +AlicesGoalMet == + /\ channel.mode = ChannelMode.CHALLENGE + /\ channel.challenge.turnNumber = LatestTurnNumber vars == << channel, submittedTX, numForces, pc >> @@ -253,7 +291,7 @@ Init == (* Global variables *) [] self = "Eve" -> "E"] Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" - /\ IF AlicesGoalUnmet \/ submittedTX # NULL + /\ IF ~AlicesGoalMet \/ submittedTX # NULL THEN /\ IF submittedTX # NULL THEN /\ IF submittedTX.type = TX_Type.FORCE_MOVE THEN /\ IF /\ channelOpen @@ -280,7 +318,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" THEN /\ IF /\ challengeOngoing /\ validTransition((submittedTX.commitment)) THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, - "Failure of assertion at line 68, column 1 of macro called at line 132, column 58.") + "Failure of assertion at line 104, column 1 of macro called at line 168, column 58.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], @@ -289,7 +327,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" ELSE /\ TRUE /\ UNCHANGED channel ELSE /\ Assert(FALSE, - "Failure of assertion at line 133, column 14.") + "Failure of assertion at line 169, column 14.") /\ UNCHANGED channel /\ submittedTX' = NULL ELSE /\ TRUE @@ -302,7 +340,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" adjudicator == Adjudicator A == /\ pc["Alice"] = "A" - /\ IF AlicesGoalUnmet + /\ IF ~AlicesGoalMet THEN /\ submittedTX = NULL /\ IF challengeOngoing THEN /\ LET turnNumber == channel.challenge.turnNumber IN @@ -313,7 +351,7 @@ A == /\ pc["Alice"] = "A" THEN /\ LET response == turnNumber + 1 IN LET commitment == [ turnNumber |-> response, signer |-> ParticipantIDX(response) ] IN /\ Assert(response \in AlicesCommitments, - "Failure of assertion at line 166, column 17.") + "Failure of assertion at line 202, column 17.") /\ submittedTX' = [ type |-> TX_Type.RESPOND, commitment |-> commitment ] ELSE /\ TRUE /\ UNCHANGED submittedTX @@ -329,7 +367,7 @@ A == /\ pc["Alice"] = "A" alice == A E == /\ pc["Eve"] = "E" - /\ IF AlicesGoalUnmet + /\ IF ~AlicesGoalMet THEN /\ \/ /\ \E n \in NumParticipants..LatestTurnNumber: \E idx \in ParticipantIDXs \ { AlicesIDX }: IF /\ channelOpen @@ -343,7 +381,7 @@ E == /\ pc["Eve"] = "E" IF /\ challengeOngoing /\ validTransition(commitment) THEN /\ Assert((commitment.turnNumber) \in Nat, - "Failure of assertion at line 68, column 1 of macro called at line 207, column 12.") + "Failure of assertion at line 104, column 1 of macro called at line 243, column 12.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], @@ -451,5 +489,5 @@ EveCannotFrontRun ==[][ ============================================================================= \* Modification History -\* Last modified Tue Sep 10 17:35:35 MDT 2019 by andrewstewart +\* Last modified Tue Sep 10 18:34:08 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From a2f8b06360813dd04bfe9921ea27539fc7933112 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 18:41:31 -0600 Subject: [PATCH 60/66] Tidy up spec a bit --- ForceMove/ForceMove.tla | 83 ++++++++++++++++------------------------- ForceMove/Utils.tla | 20 ++++++++++ 2 files changed, 53 insertions(+), 50 deletions(-) create mode 100644 ForceMove/Utils.tla diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 55b3e8c..5563795 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -1,28 +1,10 @@ ----------------------------- MODULE ForceMove ----------------------------- -EXTENDS Integers, Sequences, FiniteSets, TLC +EXTENDS Integers, TLC, Utils CONSTANTS StartingTurnNumber, NumParticipants, AlicesIDX, - NULL \* A model value representing null. - -ChannelMode == [ - OPEN |-> "OPEN", - CHALLENGE |-> "CHALLENGE" -] - -TX_Type == [ - FORCE_MOVE |-> "FORCE_MOVE", - REFUTE |-> "REFUTE", - RESPOND |-> "RESPOND" -] - -Range(f) == { f[x] : x \in DOMAIN f } -Maximum(a,b) == IF a > b THEN a ELSE b - -LatestTurnNumber == StartingTurnNumber + NumParticipants - 1 -AlicesCommitments == StartingTurnNumber..LatestTurnNumber - + NULL (***************************************************************************) (* The purpose of this specification is to outline an algorithm that *) (* guarantees that a challenge is registered on chain with turnNumber *) @@ -62,6 +44,8 @@ AlicesCommitments == StartingTurnNumber..LatestTurnNumber (* concludes on the latest state that she has. *) (***************************************************************************) +LatestTurnNumber == StartingTurnNumber + NumParticipants - 1 +AlicesCommitments == StartingTurnNumber..LatestTurnNumber ParticipantIDXs == 1..NumParticipants ParticipantIDX(turnNumber) == 1 + ((turnNumber - 1) % NumParticipants) AlicesMove(turnNumber) == ParticipantIDX(turnNumber) = AlicesIDX @@ -73,7 +57,6 @@ ASSUME /\ ~AlicesMove(LatestTurnNumber + 1) (* --algorithm forceMove - (***************************************************************************) (* Alice calls adjudicator functions by submitting a pending transaction *) (* with the function type and arguments. The adjudicator processes this *) @@ -86,7 +69,11 @@ ASSUME variables channel = [turnNumber |-> [p \in ParticipantIDXs |-> 0], mode |-> ChannelMode.OPEN, challenge |-> NULL ], submittedTX = NULL, - numForces = 0 + counter = 0 \* Auxilliary variable used in some properties and invariants. + \* We can't specify any properties that require any memory of the + \* behaviour up to the certain point (ie. the behaviour has passed through state X seven times in a row) + \* we thus have to embed the "memory" of the behaviour in the state itself, + \* if we want to check some property the depends on the history of the behaviour define challengeOngoing == channel.mode = ChannelMode.CHALLENGE @@ -146,14 +133,10 @@ if /\ progressesChannel(commitment) then channel := [ mode |-> ChannelMode.CHALLENGE, challenge |-> commitment ] @@ channel; - - \* We can't specify any properties that require any memory of the - \* behaviour up to the certain point (ie. the behaviour has passed through state X seven times in a row) - \* we have to embed the "memory" of the behaviour in the state itself. \* By incrementing the number of forceMoves that have been called, we \* multiply the number of distinct states by a large amount, but we can specify properties like \* "Eve has not submitted 5 force moves" -\* numForces := numForces + 1; +\* counter := counter + 1; end if; end macro; @@ -177,16 +160,16 @@ end process; fair process alice = "Alice" begin -(**************************************************************************** -Alice has commitments (n - numParticipants)..(n-1). She wants to end -up with commitments (n - numParticipants + 1)..n. - -She is allowed to: - - Call submitForceMove with any states that she currently has - - Call refute with any state that she has - - Call respondWithMove or respondWithMove whenever there's an active - challenge where it's her turn to move -****************************************************************************) +(***************************************************************************) +(* Alice has commitments (n - numParticipants)..(n-1). She wants to end *) +(* up with commitments (n - numParticipants + 1)..n. *) +(* *) +(* She is allowed to: *) +(* - Call submitForceMove with any states that she currently has *) +(* - Call refute with any state that she has *) +(* - Call respondWithMove or respondWithMove whenever there's an active *) +(* challenge where it's her turn to move *) +(***************************************************************************) A: while ~AlicesGoalMet do await submittedTX = NULL; @@ -263,7 +246,7 @@ end algorithm; \* BEGIN TRANSLATION -VARIABLES channel, submittedTX, numForces, pc +VARIABLES channel, submittedTX, counter, pc (* define statement *) challengeOngoing == channel.mode = ChannelMode.CHALLENGE @@ -278,14 +261,14 @@ AlicesGoalMet == /\ channel.challenge.turnNumber = LatestTurnNumber -vars == << channel, submittedTX, numForces, pc >> +vars == << channel, submittedTX, counter, pc >> ProcSet == {"Adjudicator"} \cup {"Alice"} \cup {"Eve"} Init == (* Global variables *) /\ channel = [turnNumber |-> [p \in ParticipantIDXs |-> 0], mode |-> ChannelMode.OPEN, challenge |-> NULL ] /\ submittedTX = NULL - /\ numForces = 0 + /\ counter = 0 /\ pc = [self \in ProcSet |-> CASE self = "Adjudicator" -> "Adjudicator" [] self = "Alice" -> "A" [] self = "Eve" -> "E"] @@ -318,7 +301,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" THEN /\ IF /\ challengeOngoing /\ validTransition((submittedTX.commitment)) THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, - "Failure of assertion at line 104, column 1 of macro called at line 168, column 58.") + "Failure of assertion at line 92, column 1 of macro called at line 152, column 58.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], @@ -327,7 +310,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" ELSE /\ TRUE /\ UNCHANGED channel ELSE /\ Assert(FALSE, - "Failure of assertion at line 169, column 14.") + "Failure of assertion at line 153, column 14.") /\ UNCHANGED channel /\ submittedTX' = NULL ELSE /\ TRUE @@ -335,7 +318,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" /\ pc' = [pc EXCEPT !["Adjudicator"] = "Adjudicator"] ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "Done"] /\ UNCHANGED << channel, submittedTX >> - /\ UNCHANGED numForces + /\ UNCHANGED counter adjudicator == Adjudicator @@ -351,7 +334,7 @@ A == /\ pc["Alice"] = "A" THEN /\ LET response == turnNumber + 1 IN LET commitment == [ turnNumber |-> response, signer |-> ParticipantIDX(response) ] IN /\ Assert(response \in AlicesCommitments, - "Failure of assertion at line 202, column 17.") + "Failure of assertion at line 186, column 17.") /\ submittedTX' = [ type |-> TX_Type.RESPOND, commitment |-> commitment ] ELSE /\ TRUE /\ UNCHANGED submittedTX @@ -362,7 +345,7 @@ A == /\ pc["Alice"] = "A" /\ pc' = [pc EXCEPT !["Alice"] = "A"] ELSE /\ pc' = [pc EXCEPT !["Alice"] = "Done"] /\ UNCHANGED submittedTX - /\ UNCHANGED << channel, numForces >> + /\ UNCHANGED << channel, counter >> alice == A @@ -381,7 +364,7 @@ E == /\ pc["Eve"] = "E" IF /\ challengeOngoing /\ validTransition(commitment) THEN /\ Assert((commitment.turnNumber) \in Nat, - "Failure of assertion at line 104, column 1 of macro called at line 243, column 12.") + "Failure of assertion at line 92, column 1 of macro called at line 227, column 12.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], @@ -417,7 +400,7 @@ E == /\ pc["Eve"] = "E" /\ pc' = [pc EXCEPT !["Eve"] = "E"] ELSE /\ pc' = [pc EXCEPT !["Eve"] = "Done"] /\ UNCHANGED channel - /\ UNCHANGED << submittedTX, numForces >> + /\ UNCHANGED << submittedTX, counter >> eve == E @@ -469,7 +452,7 @@ AliceMustSubmitTransactions == [][ \* inspect the trace of behaviours that violate them to verify that the model \* checker is working as intended. -EveCanGrieveAlice == numForces < 5 +EveCanGrieveAlice == counter < 5 \* Behaviours that violate this property exhibit Eve's ability to front-run: \* Alice always submits a transaction that would change the channel state, if @@ -483,11 +466,11 @@ EveCannotFrontRun ==[][ \/ channel' # channel \* By uncommenting the following line, one can inspect traces where Eve might \* have front-run Alice multiple times -\* \/ numForces <= 3 +\* \/ counter <= 3 ]_<> ============================================================================= \* Modification History -\* Last modified Tue Sep 10 18:34:08 MDT 2019 by andrewstewart +\* Last modified Tue Sep 10 18:40:14 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart diff --git a/ForceMove/Utils.tla b/ForceMove/Utils.tla new file mode 100644 index 0000000..25352d1 --- /dev/null +++ b/ForceMove/Utils.tla @@ -0,0 +1,20 @@ +------------------------------- MODULE Utils ------------------------------- +EXTENDS Integers +ChannelMode == [ + OPEN |-> "OPEN", + CHALLENGE |-> "CHALLENGE" +] + +TX_Type == [ + FORCE_MOVE |-> "FORCE_MOVE", + REFUTE |-> "REFUTE", + RESPOND |-> "RESPOND" +] + +Range(f) == { f[x] : x \in DOMAIN f } +Maximum(a,b) == IF a > b THEN a ELSE b + +============================================================================= +\* Modification History +\* Last modified Tue Sep 10 18:36:13 MDT 2019 by andrewstewart +\* Created Tue Sep 10 18:35:45 MDT 2019 by andrewstewart From 8d3a689e6920925f99f1aaf6967ae8e88cc1cd7c Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 18:49:07 -0600 Subject: [PATCH 61/66] Remove extraneous skip --- ForceMove/ForceMove.tla | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 5563795..20f55a3 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -167,8 +167,8 @@ begin (* She is allowed to: *) (* - Call submitForceMove with any states that she currently has *) (* - Call refute with any state that she has *) -(* - Call respondWithMove or respondWithMove whenever there's an active *) -(* challenge where it's her turn to move *) +(* - Call respondWithMove whenever there's an active challenge where *) +(* it's her turn to move *) (***************************************************************************) A: while ~AlicesGoalMet do @@ -203,15 +203,18 @@ begin (***************************************************************************) (* Eve can do almost anything. *) (* *) -(* - She can sign any data with any private key, except she cannot sign *) -(* a commitment with Alice's private key when the turn number is *) -(* greater than or equal to StartingTurnNumber *) -(* - She can call any adjudicator function, at any time *) -(* - She can front-run any transaction an arbitrary number of times: if *) -(* anyone else calls an adjudicator function in a transaction tx, she *) -(* can then choose to submit any transaction before tx is mined. *) -(* - She can choose not to do anything, thus causing any active *) -(* challenge to expire. *) +(* a. She can sign any data with any private key, except she cannot sign *) +(* a commitment with Alice's private key when the turn number is *) +(* greater than or equal to StartingTurnNumber *) +(* b. She can call any adjudicator function, at any time *) +(* c. She can front-run any transaction an arbitrary number of times: if *) +(* anyone else calls an adjudicator function in a transaction tx, she *) +(* can then choose to submit any transaction before tx is mined. *) +(* d. She can choose not to do anything, thus causing any active *) +(* challenge to expire. *) +(* *) +(* (d) is emulated by behaviours where execution is either *) +(* Alice->Adjudicator or Adjudicator->Alice *) (***************************************************************************) E: while ~AlicesGoalMet do @@ -236,7 +239,6 @@ while ~AlicesGoalMet do do refute(turnNumber); end with; end either; end if; - or skip; \* Eve goes offline end either; end while; end process; @@ -301,7 +303,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" THEN /\ IF /\ challengeOngoing /\ validTransition((submittedTX.commitment)) THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, - "Failure of assertion at line 92, column 1 of macro called at line 152, column 58.") + "Failure of assertion at line 93, column 1 of macro called at line 153, column 58.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], @@ -310,7 +312,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" ELSE /\ TRUE /\ UNCHANGED channel ELSE /\ Assert(FALSE, - "Failure of assertion at line 153, column 14.") + "Failure of assertion at line 154, column 14.") /\ UNCHANGED channel /\ submittedTX' = NULL ELSE /\ TRUE @@ -334,7 +336,7 @@ A == /\ pc["Alice"] = "A" THEN /\ LET response == turnNumber + 1 IN LET commitment == [ turnNumber |-> response, signer |-> ParticipantIDX(response) ] IN /\ Assert(response \in AlicesCommitments, - "Failure of assertion at line 186, column 17.") + "Failure of assertion at line 187, column 17.") /\ submittedTX' = [ type |-> TX_Type.RESPOND, commitment |-> commitment ] ELSE /\ TRUE /\ UNCHANGED submittedTX @@ -364,7 +366,7 @@ E == /\ pc["Eve"] = "E" IF /\ challengeOngoing /\ validTransition(commitment) THEN /\ Assert((commitment.turnNumber) \in Nat, - "Failure of assertion at line 92, column 1 of macro called at line 227, column 12.") + "Failure of assertion at line 93, column 1 of macro called at line 231, column 12.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], @@ -395,8 +397,6 @@ E == /\ pc["Eve"] = "E" /\ UNCHANGED channel ELSE /\ TRUE /\ UNCHANGED channel - \/ /\ TRUE - /\ UNCHANGED channel /\ pc' = [pc EXCEPT !["Eve"] = "E"] ELSE /\ pc' = [pc EXCEPT !["Eve"] = "Done"] /\ UNCHANGED channel @@ -472,5 +472,5 @@ EveCannotFrontRun ==[][ ============================================================================= \* Modification History -\* Last modified Tue Sep 10 18:40:14 MDT 2019 by andrewstewart +\* Last modified Tue Sep 10 18:47:34 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart From 64800a2becbaf222ae16e945e020df0652b20ffe Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 18:49:17 -0600 Subject: [PATCH 62/66] Add TurnNumberIncrements --- ForceMove/ForceMove.tla | 4 ++++ ForceMove/Success.cfg | 1 + 2 files changed, 5 insertions(+) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 20f55a3..436b4b7 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -448,6 +448,10 @@ AliceMustSubmitTransactions == [][ => UNCHANGED channel ]_<> +TurnNumberIncrements == [][ + \A p \in ParticipantIDXs : channel'.turnNumber[p] >= channel.turnNumber[p] +]_<> + \* It's useful to specify the following invariants or properties, since we can \* inspect the trace of behaviours that violate them to verify that the model \* checker is working as intended. diff --git a/ForceMove/Success.cfg b/ForceMove/Success.cfg index c027863..c6a55c6 100644 --- a/ForceMove/Success.cfg +++ b/ForceMove/Success.cfg @@ -23,4 +23,5 @@ PROPERTY Termination AliceCanProgressChannel AliceMustSubmitTransactions +TurnNumberIncrements \* Generated on Tue Sep 10 17:39:56 MDT 2019 \ No newline at end of file From 4eda11821bcdf246456e7f222528702c8e0fc263 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 18:55:34 -0600 Subject: [PATCH 63/66] Tidy up model definitions --- ForceMove/EveCannotFrontRun.cfg | 27 ++++++++---------------- ForceMove/Success.cfg | 27 ++++++++---------------- ForceMove/ThreeParticipants.tla | 27 +++++------------------- ForceMove/TwoParticipants.tla | 27 +++++------------------- ForceMove/TwoParticipantsLongHistory.tla | 27 +++++------------------- 5 files changed, 33 insertions(+), 102 deletions(-) diff --git a/ForceMove/EveCannotFrontRun.cfg b/ForceMove/EveCannotFrontRun.cfg index e5b3934..9e7dd6d 100644 --- a/ForceMove/EveCannotFrontRun.cfg +++ b/ForceMove/EveCannotFrontRun.cfg @@ -1,24 +1,15 @@ -\* CONSTANT declarations -CONSTANT NULL = NULL -\* CONSTANT definitions CONSTANT -StartingTurnNumber <- const_15681587964711770000 -\* CONSTANT definitions -CONSTANT -NumParticipants <- const_15681587964711771000 -\* CONSTANT definitions -CONSTANT -AlicesIDX <- const_15681587964711772000 -\* CONSTANT definition -CONSTANT -Nat <- def_ov_15681587964711773000 -\* SPECIFICATION definition +NULL = NULL +StartingTurnNumber <- const_StartingTurnNumber +NumParticipants <- const_NumParticipants +AlicesIDX <- const_AlicesIDX +Nat <- def_ov_Nat + SPECIFICATION Spec -\* INVARIANT definition + INVARIANT TypeOK -\* PROPERTY definition + PROPERTY -EveCannotFrontRun -\* Generated on Tue Sep 10 17:39:56 MDT 2019 \ No newline at end of file +EveCannotFrontRun \ No newline at end of file diff --git a/ForceMove/Success.cfg b/ForceMove/Success.cfg index c6a55c6..4e34df7 100644 --- a/ForceMove/Success.cfg +++ b/ForceMove/Success.cfg @@ -1,27 +1,18 @@ -\* CONSTANT declarations -CONSTANT NULL = NULL -\* CONSTANT definitions CONSTANT -StartingTurnNumber <- const_15681587964711770000 -\* CONSTANT definitions -CONSTANT -NumParticipants <- const_15681587964711771000 -\* CONSTANT definitions -CONSTANT -AlicesIDX <- const_15681587964711772000 -\* CONSTANT definition -CONSTANT -Nat <- def_ov_15681587964711773000 -\* SPECIFICATION definition +NULL = NULL +StartingTurnNumber <- const_StartingTurnNumber +NumParticipants <- const_NumParticipants +AlicesIDX <- const_AlicesIDX +Nat <- def_ov_Nat + SPECIFICATION Spec -\* INVARIANT definition + INVARIANT TypeOK -\* PROPERTY definition + PROPERTY Termination AliceCanProgressChannel AliceMustSubmitTransactions -TurnNumberIncrements -\* Generated on Tue Sep 10 17:39:56 MDT 2019 \ No newline at end of file +TurnNumberIncrements \ No newline at end of file diff --git a/ForceMove/ThreeParticipants.tla b/ForceMove/ThreeParticipants.tla index 2cf466b..ea1472f 100644 --- a/ForceMove/ThreeParticipants.tla +++ b/ForceMove/ThreeParticipants.tla @@ -1,25 +1,8 @@ ---- MODULE ThreeParticipants ---- EXTENDS ForceMove, TLC -\* CONSTANT definitions @modelParameterConstants:1StartingTurnNumber -const_15681587964711770000 == -5 ----- - -\* CONSTANT definitions @modelParameterConstants:2NumParticipants -const_15681587964711771000 == -3 ----- - -\* CONSTANT definitions @modelParameterConstants:3AlicesIDX -const_15681587964711772000 == -3 ----- - -\* CONSTANT definition @modelParameterDefinitions:0 -def_ov_15681587964711773000 == -0..20 ----- -============================================================================= -\* Modification History -\* Created Tue Sep 10 17:39:56 MDT 2019 by andrewstewart +const_StartingTurnNumber == 5 +const_NumParticipants == 3 +const_AlicesIDX == 3 +def_ov_Nat == 0..20 +============================================================================= \ No newline at end of file diff --git a/ForceMove/TwoParticipants.tla b/ForceMove/TwoParticipants.tla index df7d717..673c65b 100644 --- a/ForceMove/TwoParticipants.tla +++ b/ForceMove/TwoParticipants.tla @@ -1,25 +1,8 @@ ---- MODULE TwoParticipants ---- EXTENDS ForceMove, TLC -\* CONSTANT definitions @modelParameterConstants:1StartingTurnNumber -const_15681587964711770000 == -5 ----- - -\* CONSTANT definitions @modelParameterConstants:2NumParticipants -const_15681587964711771000 == -2 ----- - -\* CONSTANT definitions @modelParameterConstants:3AlicesIDX -const_15681587964711772000 == -2 ----- - -\* CONSTANT definition @modelParameterDefinitions:0 -def_ov_15681587964711773000 == -0..20 ----- -============================================================================= -\* Modification History -\* Created Tue Sep 10 17:39:56 MDT 2019 by andrewstewart +const_StartingTurnNumber == 5 +const_NumParticipants == 2 +const_AlicesIDX == 2 +def_ov_Nat == 0..20 +============================================================================= \ No newline at end of file diff --git a/ForceMove/TwoParticipantsLongHistory.tla b/ForceMove/TwoParticipantsLongHistory.tla index 6a7a0b9..ff2cee8 100644 --- a/ForceMove/TwoParticipantsLongHistory.tla +++ b/ForceMove/TwoParticipantsLongHistory.tla @@ -1,25 +1,8 @@ ---- MODULE TwoParticipantsLongHistory ---- EXTENDS ForceMove, TLC -\* CONSTANT definitions @modelParameterConstants:1StartingTurnNumber -const_15681587964711770000 == -31 ----- - -\* CONSTANT definitions @modelParameterConstants:2NumParticipants -const_15681587964711771000 == -2 ----- - -\* CONSTANT definitions @modelParameterConstants:3AlicesIDX -const_15681587964711772000 == -2 ----- - -\* CONSTANT definition @modelParameterDefinitions:0 -def_ov_15681587964711773000 == -0..64 ----- -============================================================================= -\* Modification History -\* Created Tue Sep 10 17:39:56 MDT 2019 by andrewstewart +const_StartingTurnNumber == 31 +const_NumParticipants == 2 +const_AlicesIDX == 2 +def_ov_Nat == 0..64 +============================================================================= \ No newline at end of file From 9d6f283f47e3ef029488bc5bc6507b0be09a9af5 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 18:57:12 -0600 Subject: [PATCH 64/66] Add FiveParticipants model --- ForceMove/FiveParticipants.tla | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 ForceMove/FiveParticipants.tla diff --git a/ForceMove/FiveParticipants.tla b/ForceMove/FiveParticipants.tla new file mode 100644 index 0000000..b422141 --- /dev/null +++ b/ForceMove/FiveParticipants.tla @@ -0,0 +1,8 @@ +---- MODULE FiveParticipants ---- +EXTENDS ForceMove, TLC + +const_StartingTurnNumber == 6 +const_NumParticipants == 5 +const_AlicesIDX == 3 +def_ov_Nat == 0..15 +============================================================================= \ No newline at end of file From b36a9dbaf3f7349c417922fe69fa7cf00413a5e2 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Tue, 10 Sep 2019 18:58:50 -0600 Subject: [PATCH 65/66] Add compiled spec. (Some of the algorithm overflows currently.) --- ForceMove/ForceMove.pdf | Bin 0 -> 61808 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 ForceMove/ForceMove.pdf diff --git a/ForceMove/ForceMove.pdf b/ForceMove/ForceMove.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d38c0bcfaaef4dda61d6f0cc544a25f31021fe94 GIT binary patch literal 61808 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 literal 0 HcmV?d00001 From b2936d49b37baba21f545498b7e37883e5988db4 Mon Sep 17 00:00:00 2001 From: Andrew Stewart Date: Wed, 11 Sep 2019 11:12:05 -0600 Subject: [PATCH 66/66] AlicesIDX is an algorithm variable There's no need to define it as a constant and then check that it's a participant's IDX. Plus, this way, models exhaustively check all positions of Alice in the participants array. --- ForceMove/ForceMove.tla | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ForceMove/ForceMove.tla b/ForceMove/ForceMove.tla index 436b4b7..fafa99e 100644 --- a/ForceMove/ForceMove.tla +++ b/ForceMove/ForceMove.tla @@ -3,7 +3,6 @@ EXTENDS Integers, TLC, Utils CONSTANTS StartingTurnNumber, NumParticipants, - AlicesIDX, NULL (***************************************************************************) (* The purpose of this specification is to outline an algorithm that *) @@ -48,13 +47,10 @@ LatestTurnNumber == StartingTurnNumber + NumParticipants - 1 AlicesCommitments == StartingTurnNumber..LatestTurnNumber ParticipantIDXs == 1..NumParticipants ParticipantIDX(turnNumber) == 1 + ((turnNumber - 1) % NumParticipants) -AlicesMove(turnNumber) == ParticipantIDX(turnNumber) = AlicesIDX ASSUME /\ StartingTurnNumber \in Nat /\ NumParticipants \in Nat \ { 1 } - /\ AlicesIDX \in ParticipantIDXs - /\ ~AlicesMove(LatestTurnNumber + 1) (* --algorithm forceMove (***************************************************************************) @@ -69,6 +65,7 @@ ASSUME variables channel = [turnNumber |-> [p \in ParticipantIDXs |-> 0], mode |-> ChannelMode.OPEN, challenge |-> NULL ], submittedTX = NULL, + AlicesIDX \in ParticipantIDXs \ { ParticipantIDX(LatestTurnNumber + 1) }, counter = 0 \* Auxilliary variable used in some properties and invariants. \* We can't specify any properties that require any memory of the \* behaviour up to the certain point (ie. the behaviour has passed through state X seven times in a row) @@ -83,6 +80,7 @@ validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(commitment) == /\ commitment.turnNumber = channel.challenge.turnNumber + 1 /\ commitment.signer = ParticipantIDX(commitment.turnNumber) +AlicesMove(turnNumber) == ParticipantIDX(turnNumber) = AlicesIDX AlicesGoalMet == /\ channel.mode = ChannelMode.CHALLENGE /\ channel.challenge.turnNumber = LatestTurnNumber @@ -248,7 +246,7 @@ end algorithm; \* BEGIN TRANSLATION -VARIABLES channel, submittedTX, counter, pc +VARIABLES channel, submittedTX, AlicesIDX, counter, pc (* define statement *) challengeOngoing == channel.mode = ChannelMode.CHALLENGE @@ -258,18 +256,20 @@ validCommitment(c) == c \in [ turnNumber: Nat, signer: ParticipantIDXs ] validTransition(commitment) == /\ commitment.turnNumber = channel.challenge.turnNumber + 1 /\ commitment.signer = ParticipantIDX(commitment.turnNumber) +AlicesMove(turnNumber) == ParticipantIDX(turnNumber) = AlicesIDX AlicesGoalMet == /\ channel.mode = ChannelMode.CHALLENGE /\ channel.challenge.turnNumber = LatestTurnNumber -vars == << channel, submittedTX, counter, pc >> +vars == << channel, submittedTX, AlicesIDX, counter, pc >> ProcSet == {"Adjudicator"} \cup {"Alice"} \cup {"Eve"} Init == (* Global variables *) /\ channel = [turnNumber |-> [p \in ParticipantIDXs |-> 0], mode |-> ChannelMode.OPEN, challenge |-> NULL ] /\ submittedTX = NULL + /\ AlicesIDX \in ParticipantIDXs \ { ParticipantIDX(LatestTurnNumber + 1) } /\ counter = 0 /\ pc = [self \in ProcSet |-> CASE self = "Adjudicator" -> "Adjudicator" [] self = "Alice" -> "A" @@ -303,7 +303,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" THEN /\ IF /\ challengeOngoing /\ validTransition((submittedTX.commitment)) THEN /\ Assert(((submittedTX.commitment).turnNumber) \in Nat, - "Failure of assertion at line 93, column 1 of macro called at line 153, column 58.") + "Failure of assertion at line 91, column 1 of macro called at line 151, column 58.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], ((submittedTX.commitment).turnNumber))], @@ -312,7 +312,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" ELSE /\ TRUE /\ UNCHANGED channel ELSE /\ Assert(FALSE, - "Failure of assertion at line 154, column 14.") + "Failure of assertion at line 152, column 14.") /\ UNCHANGED channel /\ submittedTX' = NULL ELSE /\ TRUE @@ -320,7 +320,7 @@ Adjudicator == /\ pc["Adjudicator"] = "Adjudicator" /\ pc' = [pc EXCEPT !["Adjudicator"] = "Adjudicator"] ELSE /\ pc' = [pc EXCEPT !["Adjudicator"] = "Done"] /\ UNCHANGED << channel, submittedTX >> - /\ UNCHANGED counter + /\ UNCHANGED << AlicesIDX, counter >> adjudicator == Adjudicator @@ -336,7 +336,7 @@ A == /\ pc["Alice"] = "A" THEN /\ LET response == turnNumber + 1 IN LET commitment == [ turnNumber |-> response, signer |-> ParticipantIDX(response) ] IN /\ Assert(response \in AlicesCommitments, - "Failure of assertion at line 187, column 17.") + "Failure of assertion at line 185, column 17.") /\ submittedTX' = [ type |-> TX_Type.RESPOND, commitment |-> commitment ] ELSE /\ TRUE /\ UNCHANGED submittedTX @@ -347,7 +347,7 @@ A == /\ pc["Alice"] = "A" /\ pc' = [pc EXCEPT !["Alice"] = "A"] ELSE /\ pc' = [pc EXCEPT !["Alice"] = "Done"] /\ UNCHANGED submittedTX - /\ UNCHANGED << channel, counter >> + /\ UNCHANGED << channel, AlicesIDX, counter >> alice == A @@ -366,7 +366,7 @@ E == /\ pc["Eve"] = "E" IF /\ challengeOngoing /\ validTransition(commitment) THEN /\ Assert((commitment.turnNumber) \in Nat, - "Failure of assertion at line 93, column 1 of macro called at line 231, column 12.") + "Failure of assertion at line 91, column 1 of macro called at line 229, column 12.") /\ channel' = [ mode |-> ChannelMode.OPEN, turnNumber |-> [p \in ParticipantIDXs |-> Maximum(channel.turnNumber[p], (commitment.turnNumber))], @@ -400,7 +400,7 @@ E == /\ pc["Eve"] = "E" /\ pc' = [pc EXCEPT !["Eve"] = "E"] ELSE /\ pc' = [pc EXCEPT !["Eve"] = "Done"] /\ UNCHANGED channel - /\ UNCHANGED << submittedTX, counter >> + /\ UNCHANGED << submittedTX, AlicesIDX, counter >> eve == E @@ -476,5 +476,5 @@ EveCannotFrontRun ==[][ ============================================================================= \* Modification History -\* Last modified Tue Sep 10 18:47:34 MDT 2019 by andrewstewart +\* Last modified Wed Sep 11 11:08:48 MDT 2019 by andrewstewart \* Created Tue Aug 06 14:38:11 MDT 2019 by andrewstewart