Theory LastVotingDefs

theory LastVotingDefs
imports "../HOModel"
begin

section ‹Verification of the \emph{LastVoting} Consensus Algorithm›

text ‹
  The \emph{LastVoting} algorithm can be considered as a representation of
  Lamport's Paxos consensus algorithm~cite"lamport:part-time"
  in the Heard-Of model. It is a coordinated algorithm designed to
  tolerate benign failures. Following~cite"charron:heardof", we formalize
  its proof of correctness in Isabelle, using the framework of theory HOModel›.
›


subsection ‹Model of the Algorithm›

text ‹
  We begin by introducing an anonymous type of processes of finite
  cardinality that will instantiate the type variable 'proc›
  of the generic CHO model.
›

typedecl Proc ― ‹the set of processes›
axiomatization where Proc_finite: "OFCLASS(Proc, finite_class)"
instance Proc :: finite by (rule Proc_finite)

abbreviation
  "N  card (UNIV::Proc set)"   ― ‹number of processes›

text ‹
  The algorithm proceeds in \emph{phases} of $4$ rounds each (we call
  \emph{steps} the individual rounds that constitute a phase).
  The following utility functions compute the phase and step of a round,
  given the round number.
›

definition phase where "phase (r::nat)  r div 4"

definition step where "step (r::nat)  r mod 4"

lemma phase_zero [simp]: "phase 0 = 0"
by (simp add: phase_def)

lemma step_zero [simp]: "step 0 = 0"
by (simp add: step_def)

lemma phase_step: "(phase r * 4) + step r = r"
  by (auto simp add: phase_def step_def)

text ‹
  The following record models the local state of a process.
›

record 'val pstate =
  x :: 'val                ― ‹current value held by process›
  vote :: "'val option"    ― ‹value the process voted for, if any›
  commt :: bool            ― ‹did the process commit to the vote?›
  ready :: bool            ― ‹for coordinators: did the round finish successfully?›
  timestamp :: nat         ― ‹time stamp of current value›
  decide :: "'val option"  ― ‹value the process has decided on, if any›
  coordΦ :: Proc           ― ‹coordinator for current phase›

text ‹
  Possible messages sent during the execution of the algorithm.
›

datatype 'val msg =
  ValStamp "'val" "nat"
| Vote "'val"
| Ack
| Null  ― ‹dummy message in case nothing needs to be sent›

text ‹
  Characteristic predicates on messages.
›

definition isValStamp where "isValStamp m  v ts. m = ValStamp v ts"

definition isVote where "isVote m  v. m = Vote v"

definition isAck where "isAck m  m = Ack"

text ‹
  Selector functions to retrieve components of messages. These functions
  have a meaningful result only when the message is of an appropriate kind.
›

fun val where
  "val (ValStamp v ts) = v"
| "val (Vote v) = v"

fun stamp where
  "stamp (ValStamp v ts) = ts"

text ‹
  The x› field of the initial state is unconstrained, all other
  fields are initialized appropriately.
›

definition LV_initState where
  "LV_initState p st crd 
     vote st = None
    ¬(commt st)
    ¬(ready st)
    timestamp st = 0
    decide st = None
    coordΦ st = crd"

text ‹
  We separately define the transition predicates and the send functions
  for each step and later combine them to define the overall next-state relation.
›

― ‹processes from which values and timestamps were received›
definition valStampsRcvd where
  "valStampsRcvd (msgs :: Proc  'val msg) 
   {q . v ts. msgs q = Some (ValStamp v ts)}"

definition highestStampRcvd where
  "highestStampRcvd msgs  
   Max {ts . q v. (msgs::Proc  'val msg) q = Some (ValStamp v ts)}"

text ‹
  In step 0, each process sends its current x› and timestamp›
  values to its coordinator.

  A process that considers itself to be a coordinator updates its
  vote› field if it has received messages from a majority of processes.
  It then sets its commt› field to true.
›

definition send0 where
  "send0 r p q st 
   if q = coordΦ st then ValStamp (x st) (timestamp st) else Null"

definition next0 where
  "next0 r p st msgs crd st' 
      if p = coordΦ st  card (valStampsRcvd msgs) > N div 2
      then (p v. msgs p = Some (ValStamp v (highestStampRcvd msgs))
                 st' = st  vote := Some v, commt := True  )
      else st' = st"

text ‹
  In step 1, coordinators that have committed send their vote to all
  processes.

  Processes update their x› and timestamp› fields if they
  have received a vote from their coordinator.
›

definition send1 where
  "send1 r p q st 
   if p = coordΦ st  commt st then Vote (the (vote st)) else Null"

definition next1 where
  "next1 r p st msgs crd st' 
   if msgs (coordΦ st)  None  isVote (the (msgs (coordΦ st)))
   then st' = st  x := val (the (msgs (coordΦ st))), timestamp := Suc(phase r) 
   else st' = st"

text ‹
  In step 2, processes that have current timestamps send an acknowledgement
  to their coordinator.

  A coordinator sets its ready› field to true if it receives a majority
  of acknowledgements.
›

definition send2 where
  "send2 r p q st 
   if timestamp st = Suc(phase r)  q = coordΦ st then Ack else Null"

― ‹processes from which an acknowledgement was received›
definition acksRcvd where
  "acksRcvd (msgs :: Proc  'val msg) 
   { q . msgs q  None  isAck (the (msgs q)) }"

definition next2 where
  "next2 r p st msgs crd st' 
   if p = coordΦ st  card (acksRcvd msgs) > N div 2
   then st' = st  ready := True 
   else st' = st"

text ‹
  In step 3, coordinators that are ready send their vote to all processes.

  Processes that received a vote from their coordinator decide on that value.
  Coordinators reset their ready› and commt› fields to false.
  All processes reset the coordinators as indicated by the parameter of
  the operator.
›

definition send3 where
  "send3 r p q st 
   if p = coordΦ st  ready st then Vote (the (vote st)) else Null"

definition next3 where
  "next3 r p st msgs crd st' 
      (if msgs (coordΦ st)  None  isVote (the (msgs (coordΦ st)))
       then decide st' = Some (val (the (msgs (coordΦ st))))
       else decide st' = decide st)
    (if p = coordΦ st
      then ¬(ready st')  ¬(commt st')
      else ready st' = ready st  commt st' = commt st)
    x st' = x st
    vote st' = vote st
    timestamp st' = timestamp st
    coordΦ st' = crd"

text ‹
  The overall send function and next-state relation are simply obtained as
  the composition of the individual relations defined above.
›

definition LV_sendMsg :: "nat  Proc  Proc  'val pstate  'val msg" where
  "LV_sendMsg (r::nat) 
   if step r = 0 then send0 r
   else if step r = 1 then send1 r
   else if step r = 2 then send2 r
   else send3 r"


definition
  LV_nextState :: "nat  Proc  'val pstate  (Proc  'val msg) 
                        Proc  'val pstate  bool"
  where
  "LV_nextState r 
   if step r = 0 then next0 r
   else if step r = 1 then next1 r
   else if step r = 2 then next2 r
   else next3 r"


subsection ‹Communication Predicate for \emph{LastVoting}›

text ‹
  We now define the communication predicate that will be assumed for the
  correctness proof of the \emph{LastVoting} algorithm.
  The ``per-round'' part is trivial: integrity and agreement are always ensured.

  For the ``global'' part, Charron-Bost and Schiper propose a predicate
  that requires the existence of infinitely many phases ph› such that:
  \begin{itemize}
  \item all processes agree on the same coordinator c›,
  \item c› hears from a strict majority of processes in steps 0 and 2
    of phase ph›, and
  \item every process hears from c› in steps 1 and 3 (this is slightly
    weaker than the predicate that appears in~cite"charron:heardof", but
    obviously sufficient).
  \end{itemize}

  Instead of requiring infinitely many such phases, we only assume the
  existence of one such phase (Charron-Bost and Schiper note that this is enough.)
›

definition
  LV_commPerRd where
  "LV_commPerRd r (HO::Proc HO) (coord::Proc coord)  True"

definition
  LV_commGlobal where
  "LV_commGlobal HOs coords 
      ph::nat. c::Proc.
           (p. coords (4*ph) p = c)
          card (HOs (4*ph) c) > N div 2
          card (HOs (4*ph+2) c) > N div 2
          (p. c  HOs (4*ph+1) p  HOs (4*ph+3) p)"


subsection ‹The \emph{LastVoting} Heard-Of Machine›

text ‹
  We now define the coordinated HO machine for the \emph{LastVoting} algorithm
  by assembling the algorithm definition and its communication-predicate.
›

definition LV_CHOMachine where
  "LV_CHOMachine 
     CinitState = LV_initState,
      sendMsg = LV_sendMsg,
      CnextState = LV_nextState,
      CHOcommPerRd = LV_commPerRd,
      CHOcommGlobal = LV_commGlobal "

abbreviation 
  "LV_M  (LV_CHOMachine::(Proc, 'val pstate, 'val msg) CHOMachine)"

end