# Paxos

Here are four versions of Paxos, three believed correct and one known broken.

## Paxos-A

``````persistent state
proposer: n_p (initially 0) --- the latest proposal round
acceptor: n_l (initially 0) --- the largest round received in a prepare()
acceptor: n_a (initially 0) --- the largest round received in an accept()
acceptor: v_a (initially NULL) --- the value received by the accept() for n_a

volatile state at proposer
a --- number of responses received
n_o --- the largest round received in a prepared()
v_o --- the value received by the prepared() for n_o

propose: (at proposer)
n_p := n_p + 1 + uniqueifier()
a := 0         // volatile state
n_o := 0
send prepare(n_p) to a majority of acceptors

n_l := max(n_l, n)
send prepared(n_a, v_a) to proposer

if n > n_o:
n_o := n
v_o := v
a := a + 1
if a = f + 1:
if v_o = NULL:
v_o := choose value
a := 0
n_p := max(n_p, n_o)
send accept(n_p, v_o) to a majority of acceptors

if n >= n_l:
n_l := n_a := n
v_a := v
send accepted(n_a) to proposer

if n = n_p:
a := a + 1
if a = f + 1:
send decided(v_o) to all

timeout: (at proposer)
call propose() again
``````

In Bad Paxos, we do not store n_l; instead we overload n_a and make n_a := max(n_l, n_a). This implementation is incorrect. Can you design an example execution that demonstrates this incorrectness?

``````persistent state
proposer: n_p (initially 0) --- the latest proposal round
acceptor: n_a (initially 0) --- the largest round received in an
accept() or prepare()
acceptor: v_a (initially NULL) --- the value received by the accept() for n_a

volatile state at proposer
a --- number of responses received
n_o --- the largest round received in a prepared()
v_o --- the value received by the prepared() for n_o

propose: (at proposer)
n_p := n_p + 1 + uniqueifier()
a := 0         // volatile state
n_o := 0
send prepare(n_p) to a majority of acceptors

n_a := max(n_a, n)
send prepared(n_a, v_a) to proposer

n_o := max(n_o, n)
if n = n_o and v != NULL:
v_o := v
a := a + 1
if a = f + 1:
if v_o = NULL:
v_o := choose value
a := 0
send accept(n_o, v_o) to a majority of acceptors

if n >= n_a:
n_a := n
v_a := v
send accepted(n_a) to proposer

if n = n_o:
a := a + 1
if a = f + 1:
send decided(v_o) to all

timeout: (at proposer)
call propose() again
``````

## Paxos-B

Many implementations of the Paxos idea are possible, and differences among them are useful to consider. Here’s an alternate choice, Paxos-B, which is closer to Robert Morris’s pseudocode.

``````persistent state
proposer/acceptor: n_l (initially 0) --- the largest round received in a prepare()
acceptor: n_a (initially 0) --- the largest round received in an accept()
acceptor: v_a (initially NULL) --- the value received by the accept() for n_a

volatile state at proposer
n_p --- round of current proposal
a --- number of prepared/accepted messages received
n_o --- latest known prepared round
v_o --- latest known prepared value

propose: (at proposer)
n_p := n_l + 1 + uniqueifier()   // overlap between proposer state and acceptor state
a := 0
n_o := 0
send prepare(n_p) to a majority of acceptors, *including self*

if n > n_l:
n_l := n
send prepared(n_a, v_a) to acceptor

if n > n_o:
n_o := n
v_o := v
a := a + 1
if a = f + 1:
if v_o = NULL:
v_o := choose value
a := 0
send accept(n_p, v_o) to majority of servers

if n >= n_l:
n_l := n_a := n
v_a := v
send accepted(n) to proposer

a := a + 1
if a = f + 1:
send decided(v_o) to all
``````

Questions:

• It is critically important that the propose step include the collocated acceptor in the set of acceptors to which it sends prepare. Why?
• Paxos-B acceptors do not respond to failed prepare and accept messages. Paxos-A acceptors, in contrast, respond with enough information for the proposer to detect failure. What are the advantages and disadvantages of each approach?

## Paxos-C

In this Paxos implementation, the proposer doesn’t pre-select a majority; instead, it sends prepare and accept messages to all acceptors, and takes the first majority that arrives. As a result, the pseudocode must handle prepared messages that arrive from stragglers while the protocol is accepting.

``````persistent state
proposer/acceptor: n_l (initially 0) --- the largest round received in a prepare()
acceptor: n_a (initially 0) --- the largest round received in an accept()
acceptor: v_a (initially NULL) --- the value received by the accept() for n_a

volatile state
proposer: n_p --- round of current proposal
proposer: a --- number of prepared/accepted messages received
proposer: n_o --- latest known prepared round
proposer: v_o --- latest known prepared value

propose: (at proposer)
n_p := n_l := n_l + 1 + uniqueifier()   // n_p is volatile; overlap between proposer state and acceptor state
a := 1
n_o := 0
send prepare(n_p) to all acceptors except self

if n > n_l:
n_l := n
send prepared(n_a, v_a) to acceptor

if n_p = n_l and n_p ≠ n_a:   // a straggler’s prepared will arrive when n_p = n_a already
if n > n_o:
n_o := n
v_o := v
a := a + 1
if a = f + 1:
if v_o = NULL:
v_o := choose value
a := 1
n_a := n_p
v_a := v_o
send accept(n_p, v_o) to all acceptors except self

if n >= n_l:
n_l := n_a := n
v_a := v
send accepted(n) to proposer