98 lines
No EOL
4.8 KiB
Markdown
98 lines
No EOL
4.8 KiB
Markdown
# 9.2 Alternating Bit protocol: the protocol
|
|
|
|
A and B communicate over two lossy channels AtoB and BtoA.
|
|
|
|
A sends a value. Since the channels are lossy, A keeps sending it.
|
|
Meanwhile, B acknowledges the value it receives by sending its bit (0 or 1).
|
|
Similarly, since the channels are lossy, it keeps sending it too.
|
|
|
|
When B receives a message, it knows this is a new value because the bit is different
|
|
from its current one, and starts sending the new one. When A eventually receives
|
|
a bit that differs from the one it holds, it knows that the message was successfully
|
|
transmitted. It can then go one to transmit the next message.
|
|
|
|
## Checking safety
|
|
|
|
Because the protocol is not terminating, the behaviors are infinitely long,
|
|
so TLC will fail to check them all in finite time.
|
|
|
|
To work around this we can add a state constraint like `Len(AtoB) <= 3 /\ Len(BtoA) <= 3`
|
|
|
|
However, although the toolbox exposes this, it is not directly supported by TLC:
|
|
the toolbox does it by creating its own on-the-fly spec `MC.tla`, in which it
|
|
adds a new predicate. Without the toolbox, we have to add it in the spec, like
|
|
`CheckLimits == Len(AtoB) <= 4 /\ Len(BtoA) <= 4`,
|
|
then the CFG file can contain `CONSTRAINT CheckLimits`.
|
|
|
|
This will cause TLC to only check states matching that state constraint.
|
|
|
|
We can check that AB implements its high-level spec ABSpec
|
|
so formula `Spec` in module AB should imply formula `Spec` in module ABSpec:
|
|
this should be a theorem of module AB.
|
|
|
|
We cannot use `INSTANCE ABSpec` in module AB because it imports definitions
|
|
of `Spec` and others, which already exist in module AB, so we shall use a namespace
|
|
to avoid name clashes: `ABS == INSTANCE ABSpec`, so now we can access
|
|
the definition os `Spec` in module ABSpec as `ABS!Spec`, avoiding name clashes.
|
|
This enables us to write theorem: `THEOREM Spec => ABS!Spec`.
|
|
|
|
## Checking liveness
|
|
|
|
We want fairness properties implying that messages keep getting sent and received,
|
|
meaning `THEOREM FairSpec => ABS!FairSpec`.
|
|
|
|
We cannot just require weak fairness of the Next action: for example, it would
|
|
allow a behavior in which B keeps sending the same bit forever, and nothing else:
|
|
since this is not stuttering, it would be a valid behavior.
|
|
|
|
Next is defined as the union of ASnd, ARcv, BSnd, BRcv, and LoseMsg, so we need
|
|
fairness requirements on each send and receive action. We do not need fairness
|
|
on LoseMsg, because we do not want to require that messages be lost.
|
|
|
|
If we require only weak fairness from ASnd and BSnd and all messages are lost,
|
|
weak fairness is satisfied, but the protocol is not live. Similarly, ARcv and BRcv
|
|
alternate between being enabled when the other sends, and being disabled when
|
|
these messages are lost. So weak fairness is true for them too because ARcv and BRcv
|
|
are never continuously enabled.
|
|
|
|
We need to require strong fairness for the receive actions, so that if a message
|
|
is sent, it will eventually be received.
|
|
|
|
So the behavior satisfies
|
|
```tla+ code fragment
|
|
FairSpec == Spec /\ WF_vars(ARcv) /\ WF_vars(BRcv) /\
|
|
WF_vars(ASnd) /\ WF_vars(BSnd)
|
|
```
|
|
|
|
But it does not satisfy `ABS!FairSpec`. We need to add strong fairness requirement
|
|
on some messages being eventually received. Since ASnd and BSnd are always enabled,
|
|
with no requirement, they does not need a strong fairness requirement.
|
|
|
|
## What good is liveness?
|
|
|
|
- Is it useful to know if something eventually happens, if it can happen after the end of the universe?
|
|
- How can we ensure strong fairness in practice for the ARcv and BRcv actions?
|
|
- Or even know that it is not satisfied ?
|
|
|
|
Specifications are abstractions. As such, they are a compromise beween our desires
|
|
for accuracy and reasonable simplicity. Specifying transmission delays, success rates, etc,
|
|
would complexify the spec a lot, so it is simpler to just require that it eventually be received:
|
|
if it fails being eventually received, it will not be received in any given finite time anyway.
|
|
|
|
For system without hard real-time requirements (rockets, pacemakers, etc), liveness
|
|
checking is a useful enough way to find errors that prevent things from happening.
|
|
|
|
Many systems use timeouts only to ensure that something must happen eventually.
|
|
Correctness of such a system does not depend on how long it takes for the timeout to occur:
|
|
that only influences performance, not correctness.
|
|
|
|
Specifying such systems can describe the timeouts as actions with no time constraints,
|
|
only weak fairness conditions. This is true for most systems with no bounds on how
|
|
long it can take an enabled operation (e.g. receiving a message) to occur.
|
|
|
|
Liveness is subtle and hard to get right, but safety is most often by far the
|
|
most important part of specs, and liveness is often added mostly to catch errors
|
|
in the safety part.
|
|
|
|
Fairness conditions do NOT imply the _eventually_ or _leads to_ properties
|
|
one could expect, possibly because the safety part would not allow those. |