Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port Invariants from AsyncRaft.tla #5678

Open
lemmy opened this issue Sep 21, 2023 · 0 comments
Open

Port Invariants from AsyncRaft.tla #5678

lemmy opened this issue Sep 21, 2023 · 0 comments
Labels

Comments

@lemmy
Copy link
Collaborator

lemmy commented Sep 21, 2023

The following invariants have been extracted from Will's AsyncRaft.tla specification, and confirmed to hold for ccfraft.

\* The set of servers that agree up through index.
Agree(i, index) == {i} \cup {k \in Servers : matchIndex[i][k] >= index }

\* If matchIndex on a leader has quorum agreement on an index, then this entry must
\* be present on a quorum of Servers.
H_LeaderMatchIndexValid == 
    \A s \in { s \in Servers : state[s] = Leader} :
        \A ind \in DOMAIN log[s] :
            \E Q \in Quorums[CurrentConfiguration(s)] :
                \A t \in Q :
                    (Agree(s, ind) \in Q ) => 
                         /\ ind \in DOMAIN log[t]
                         /\ log[t][ind] = log[s][ind]

H_CommitIndexCoversEntryImpliesExistsOnQuorum == 
    \A s \in Servers :
        (commitIndex[s] > 0) => 
            \E Q \in Quorums[CurrentConfiguration(s)] :
            \A t \in Q :
                /\ Len(log[s]) >= commitIndex[s] 
                /\ Len(log[t]) >= commitIndex[s] 
                /\ log[t][commitIndex[s]] = log[s][commitIndex[s]]

\* Match index records for a leader must always be <= its own log length.
H_LeaderMatchIndexBound == 
    \A s \in Servers : (state[s] = Leader) => 
        \A t \in Servers : matchIndex[s][t] <= Len(log[s])

\* Commit index is no greater than the log length on any node.
H_CommitIndexBoundValid == 
    \A s \in Servers : commitIndex[s] <= Len(log[s])

H_CurrentTermAtLeastAsLargeAsLogTerms == 
    \A s \in Servers : 
        (\A i \in DOMAIN log[s] : currentTerm[s] >= log[s][i].term)

\* If two nodes are in the same term, then their votes granted
\* sets cannot have intersecting voters.
H_CandidateVotesGrantedInTermAreUnique ==
    \A s,t \in Servers :
        (/\ s # t
         /\ state[s] = Candidate
         /\ state[t] = Candidate
         /\ currentTerm[s] = currentTerm[t]) =>
            (votesGranted[s] \cap votesGranted[t]) = {}

\* If a node has garnered votes in a term as candidate, there must
\* be no other leader in that term in existence.
H_CandidateWithVotesGrantedInTermImplyNoOtherLeader ==
    \A s,t \in Servers :
        (/\ s # t
         /\ state[s] = Candidate
         /\ votesGranted[s] \in Quorums[CurrentConfiguration(s)] 
         /\ currentTerm[s] = currentTerm[t]) =>
            state[t] # Leader

----

INVARIANT
    ...
    H_LeaderMatchIndexValid
    H_CommitIndexCoversEntryImpliesExistsOnQuorum
    H_LeaderMatchIndexBound
    H_CommitIndexBoundValid
    H_CurrentTermAtLeastAsLargeAsLogTerms
    H_CandidateVotesGrantedInTermAreUnique
    H_CandidateWithVotesGrantedInTermImplyNoOtherLeader   

This one looks interesting but doesn't hold:

\* If a commit index covers a log entry in some term,
\* then no primary in an earlier term can be enabled to commit any entries
\* in its own log.
H_CommitIndexAtEntryInTermDisabledEarlierCommits == 
    \A s,t \in Servers :
        (/\ s # t 
         /\ commitIndex[s] > 0
         /\ state[t] = Leader
         /\ currentTerm[t] < log[s][commitIndex[s]].term) =>
                \A ind \in DOMAIN log[t] : 
                    Agree(t, ind) \notin Quorums[CurrentConfiguration(s)]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant