Binary Byzantine Agreement tries to solve consensus problem in asynchronous distributed systems where processes or node can commit Byzantine failures. A process can have a Byzantine behavior when it arbitrary deviates from its intended behavior, it then commits a Byzantine failure.
This bad behavior can be intentional or simply the result of temporary fault that altered the its normal behavior in unpredictable way. One example of bad behavior is crash of process.
The Binary Byzantine consensus problem is that each correct process p(i)
proposes a value v(i)
(0 or 1). And each of members in network has to decide a value such that the following properties are satisfied:
- A decided value was proposed by a correct process
- No two correct processes decide different values
- A correct process decides at most once.
- Each correct process decides, and terminate consensus
These properties states that value proposed only by faulty node can be decided. In other words, if all correct processes propose the same value v
, the value v'
cannot be decided.
The requirements for this algorithm to work is if n
is the number of members that engaged in the agreement, the number of failed member t
must satisfies n > 3t
condition.
In a BV-broadcast, each correct process p
BV-broadcasts a binary value and obtains binary values. To store the values obtained by other processes, BV-broadcast provides binValues
, which initialized to zero-set, which increases when new values are received. And BV-broadcast follows four properties:
- If at least
t + 1
correct processes BV-broadcast the same valuev
,v
is added to the setbinValues
of each correct processp
- If
p
is correct andv
is contained inbinValues
, thenv
has been BV-broadcast by a correct process. - If a value
v
is added to the setbinValues
, of correct processp
, eventuallyv
which is contained inbinValues
is added tobinValues
at every correct processes. - Eventually the set
binValues
of each correct processp
is not empty
func BVBroadcast(v binary) {
broadcast(BVal(v))
go func() {
for {
select {
case bVal := <- bValChan:
if bVal received from (t+1) diff processes && !isBroadcast(bVal) {
broadcast(bVal)
continue;
}
if bVal received from (2t+1) diff processes {
binValues.Union(bVal)
}
}
}
}()
}
- Suppose
v
is a value such thatt+1
correct processes invokeBVBroadcast
, eventuallyt+1
correct processes receive messages. And because one node exactly receivet+1
messages from distinct processes (include myself), it broadcastbVal
to all processes. As resultbVal received from (2t+1) diff processes
executed andv
is added tobinValues
of all correct processes - As there are at least
n-t
correct processes, each of them invokesBVBroadcast
,n-t >= 2t+1 = (t+1) + t
, and there's at leastt+1
correct processes, which enables adding value tobinValues
func propose(v binary) {
estimated := v
round := 0
for {
round++
binValues := BinValues{}
// result of this function is saved at binValues()
BVBroadcast(Est(round, estimated))
waitUntil(func() {
return binValues.Size() != 0
})
for _, w := range binValues(r) {
broadcast(Aux(round, w))
}
waitUntil(func() {
// wait until set of (n - t) Aux(r, x) messages delivered from
// distinct processes where values is the set of values x
// carried by these (n - t) messages
})
coin := random()
if (len(values) == 1) {
if (values[0] == coin && !done) {
decide(values[0])
}
estimated = values[0]
} else {
estimated = coin
}
}
}
It requires t < n/3 to be tolerated. A process p
invokes proposes propose(v)
. v
is one of 0 or 1. It decides its final value when it executes statement decide(v)
.
- The local variable
estimated
of a processp
keeps its current estimate of the decision. - The process proceed by consecutive asynchronous rounds and
BVBroadcast
call is associated with each round. r
states the current round of processp
binValues
is set of binary values used forBVBroadcast
result
r++
// result of this function is saved at binValues
BVBroadcast(Est(round, est))
waitUntil(func() {
return binValues.Size() != 0
})
- During a round
round
a processp
first invokesBVBroadcast(Est(round, est))
**to inform the other processes of the value of its current estimateest
** - Then
p
waits until itsbinValues
no longer empty. Due to BV-Termination property, this eventually happens. - When the predicate becomes satisfied,
binValues
contains at least one value: 0 or 1 - Due to the BV-Justification property, the values in
binValues
wereBVBroadcast
by correct processes
for _, w := range binValues {
broadcast(Aux(round, w))
}
waitUntil(func() {
// wait until set of (n - t) Aux(round, x) messages delivered from
// distinct processes where values is the set of values x
// carried by these (n - t) messages
})
- Each correct process
p
invokesbroadcast(Aux(round, w))
wherew
is a value that belongs tobinValues
. - Byzantine process can broadcast an arbitrary binary value. So this phase is for informing other processes of estimated values of estimate values that have been
BVBroadcast
by correct processes - Wait until
n - t
messages delivered from distinct processes, for discarding values sent only by Byzantine processes. And value sent byn - t
messages saved tovalues
. values
contains only the values originated from correct processes. In other words, the setvalues
cannot contain value broadcast only by Byzantine processes.- If both
p_i
andp_j
are correct processes, and ifvalues_i = {v}
andvalues_j = {w}
for roundr
, thenv = w
- Because
p_i
hasvalues_i = {v}
,p_i
has received the same messageAux(round, v)
from at leastn - t
different processes. - Because at most
t
processes can be Byzantine, it follows thatp_i
receivedAux(round, v)
from at leastn - 2t
different correct processes. - Because
n - 2t >= t + 1
,p_i
received at least fromt + 1
correct processes - And another correct process
p_j
hasvalues_j = {w}
, which received fromAux(round, w)
from at leastn - t
different processes - Because
(n - t) + (t + 1) > n
, at least one correct process, let's sayp_x
, sentAux(round, v)
top_i
andAux(round, w)
top_j
. - Since
p_x
is correct, it sent the same message to all processes. Thereforev = w
- Because
coin := random()
if (len(values) == 1) {
if (values[0] == s && !done) {
decide(values[0])
}
estimated = values[0]
} else {
estimated = coin
}
-
coin
is network global entity that delivers the same sequence of random bitsb(1), b(2), ..., b(r)
to processes and eachb(r)
has the value 0 or 1 with probability 1/2.- In addition to being random, this bit has to following global property. the
r
th invocation ofrandom()
by a correct processp
, returns it the bitb(r)
, it means that the r times call ofrandom()
makes return valuecoin
to all of correct processes. coin
, a common coin is built in such a way that the correct processes need to cooperate to compute the value of each bitb(r)
.
- In addition to being random, this bit has to following global property. the
-
Correct process
p_i
obtains the common coin valuecoin
associated with the current round- In the case of
len(values) == 2
, it means that both the value 0 and 1 are estimate values of correct processes, thenp
adopts the valuecoin
of the common coin - In the case of
len(values) == 1
andcoin == v
, thendecide(values[0])
Otherwise it adoptsvalues[0]
as its new estimate
- In the case of
-
function
decide
allowsp
to decide but does not stop its execution. A process executes round forever. -
A decided value is a value proposed by a correct process
-
No two correct processes decide different values
This Binary Byzantine Agreement algorithm suited to asynchronous systems composed of n
processes, and where up to t < n/3
processes may have a Byzantine behavior. This algorithm use Rabin's common coin and BV-broadcast algorithm, both of which helps to guarantee a value broadcast only by Byzantine processes is never agreeed to the correct processes.