mpstk: the MultiParty Session Types toolKit
mpstk is a toolkit
for specifying multiparty protocols
and verifying their properties
(e.g., deadlock-freedom and liveness).
mpstk is based on the
new, generalised theory of multiparty session types
presented in the companion paper:
Alceste Scalas and Nobuko Yoshida.
Less is More:
Multiparty Session Types Revisited.
POPL 2019.
Software requirements
NOTE: if you are using the preconfigured
virtual machine of the POPL'19 artifact, you can skip this
section and jump to the usage instructions.
The following software packages must be installed in order to
compile and use mpstk:
mpstk has been tested on GNU/Linux
(Ubuntu 16.04 and 18.04), and its code is written with portability
in mind. It should run on other operating systems (especially
Unix-like ones) with little or no adaptations.
Compiling
Simply run:
sbt package
The build system will automatically download
all mpstk dependencies (including the
Scala compiler, and its runtime).
Usage
Currently, mpstk provides two tools:
The toolkit supports two types of protocol specification:
-
global types
(file extension: .global),
with a syntax based on Definitions 3.1 (Table 1) and 2.4 of the
companion paper;
-
session typing contexts
(file extension: .ctx),
with a syntax based on Definitions 2.6 and 2.4 of the companion
paper.
mpstk includes various examples:
they are illustrated below.
Reproducing the results in the companion paper
Reproducing Tables 4 and 5
The following scripts allow to easily reproduce Tables 4 and 5 of
the companion paper (between parentheses, the expected
execution time on an Intel Core i7 CPU @3.60 GHz).
-
./bin/popl19-table4
(30 seconds).
Produces Table 4, except the first column,
with label “consistent”.
mpstk does not currently implement
consistency checks (Table 1, Definition 3.7), since the main
goal of the companion paper is to remove the need for
consistency. Note that one of the paper's result is that
consistency is subsumed by safety (Lemma 5.9), and the latter is
supported by the tool.
-
./bin/popl19-table5-fast
(90 seconds).
Produces a rough version of Table 5: no states count, and
measurements based on 3 repetitions (instead of 30).
-
./bin/popl19-table5
(15 minutes).
Produces the full contents of Table 5.
Note that the table includes the number of states of the
multiparty protocol being verified: this requires the
explicit generation of the protocol transition system
(via mCRL2's tool lps2lts),
which is a rather expensive operation.
In all cases, it is possible to save the results in CSV format,
simply by adding the option
--output-csv=<CSVFILE> when
invoking the scripts. For more details, see
./bin/mpstk verify --help.
Variations of Table 5
Table 5 in the companion paper measures the time needed
by mpstk to verify a specification
against a property; in particular, it measures the time needed to
invoke mCRL2's tool pbes2bool, and
retrieve its result. This is the dominating time in the
verification procedure.
mpstk can produce two other related
measurements, through the option
--benchmark-type=<T>
— where <T> can be either:
-
realtime: measures the wall clock
time used by mCRL2's pbes2bool tool,
without the overhead introduced by the JVM when calling external
programs. This benchmark type uses the
time utility,
available on all POSIX-compliant systems.
-
endtoend: measures the whole time
needed to parse a .global
or .ctx file, turn it into an mCRL2
specification, create the necessary temporary files, and perform
the verification. This measurement takes into account the
maximum overhead introduced by mpstk
internals.
The results of all benchmark variants should be very
similar: realtime should be (on
average) around 1% faster than the default benchmark,
while endtoend should be around 1%
slower.
Verifying other examples
The examples/
directory contains all the examples in the companion paper, and
more. Some files have descriptive names, while others refer to
their position in the paper:
instrument-control.ctx
|
Deadlocked typing context, taken from Example 3.10 of this JACM paper.
|
instrument-control-fixed.global
|
Adaptation (with bugfix) of Example 3.10 of this JACM paper.
|
multiparty-game.global
|
Running example from this ECOOP'17 paper.
|
multiparty-workers.ctx
|
Table 2, protocol 4 (“independent multiparty workers”).
|
oauth2.global
|
Opening example in Section 1.
|
payload-subtype.ctx
|
Small example used to
explain how mpstk
handles subtyping.
|
popl19-ex5.11-a.ctx
|
Example 5.11, case ΓA.
|
popl19-ex5.11-b.ctx
|
Example 5.11, case ΓB.
|
popl19-ex5.11-c.ctx
|
Example 5.11, case ΓC.
|
popl19-ex5.6.ctx
|
Example 5.6.
|
popl19-ex5.7.ctx
|
Example 5.7.
|
popl19-sec2.3.ctx
|
The unsafe typing context discussed in Section 2.3.
|
popl19-sec5.ctx
|
The safe, but deadlocked, typing context discussed in the
opening of Section 5.
|
popl19-sec7-m3.ctx
|
The safe, but deadlocked, typing context discussed in Section
7, point (M3).
|
rec-map-reduce.ctx
|
Table 2, protocol 3 (“recursive map/reduce”).
|
rec-two-buyers.ctx
|
Table 2, protocol 2 (“recursive two-buyer”).
|
two-buyers.global
|
Classic two-buyer protocol from session types literature,
taken from this POPL'08 paper (Section 3.2)
and this JACM paper (Example 3.8).
|
streaming.global
|
Simple streaming protocol
taken from this POPL'08 paper (Section 3.2)
and this JACM paper (Example 3.9).
|
All examples can be verified by invoking the tool as expected, e.g.:
./bin/mpstk verify examples/popl19-ex5.11-c.ctx
Additionally,
the examples-bad/
directory contains various global types that are not projectable,
according to Definition 3.2 in the companion paper.
For more details, one can invoke, e.g.:
./bin/mpstk project examples-bad/instrument-control.global
and see the resulting error messages: they show which projections
are not defined, and why.
Checking the implementation of Table 3
The multiparty session typing context properties verified
by mpstk are implemented
as mCRL2 µ-calculus formulas,
by strictly following the definitions of Table 3 in the companion paper.
Each property is defined as a .mcf file,
and is provided as part of
the program resources:
By visually inspecting the contents of
the .mcf files above, it should be
possible to grasp their direct correspondence with Table 3 in the
companion paper. Still, such .mcf files
use several mCRL2 sorts
(e.g., Session, Role,
Message, ...) that are defined elsewhere.
For more details, please see how session
typing contexts are encoded in mCRL2.
Behind the scenes
API documentation
To build the API documentation, invoke:
sbt doc
The resulting documentation will be available in
target/scala-2.12/api/mpstk/
(online copy).
Overview of the mpstk source code
This section provides a brief description of
each mpstk source code file.
Core data structures
-
GlobalType.scala: representation of a global session type.
-
MPST.scala: representation of a multiparty session type.
-
Context.scala: representation of a multiparty session typing context.
-
Ops.scala:
implementation of most operations involving global
types, session types, and typing contexts (e.g., substitutions,
unfolding, Barendregt convention...).
-
Subtyping.scala:
implementation of the subtyping algorithm for multiparty session
types.
-
RawMPST.scala:
this file contains a “raw” representation of
multiparty session types, and typing contexts: they do not
follow the syntactic constraints formalised in the companion
paper, and are used internally as an intermediate step, to
generate the mCRL2 encoding of typing
contexts.
-
Parser.scala:
parsers for global types and typing contexts,
based on the Scala standard parser combinators library.
-
Util.scala:
miscellaneous utility methods.
mCRL2 encoding and verification
-
mcrl2/Spec.scala:
representation of a multiparty session typing context as a mCRL2
specification. This files implements the encoding strategy
described below.
-
mcrl2/Property.scala:
representation of typing context properties. Each property
corresponds to a .mcf file
(mCRL2 µ-calculus formula) available among
the program resources;
moreover, each such .mcf file
corresponds to a µ-calculus formula defined on Table 3 in the
companion paper.
-
mcrl2/Verifier.scala:
a Verifier object checks whether a
given Spec instance satisfies a given
set of Property instances. This is the
main interface to mCRL2: a Verifier
handles the creation of temporary files, launches mCRL2 tools as
needed, reads their output, returns their result, and performs
benchmarks.
Tools
Extending mpstk
mpstk can be easily extended to verify
new behavioural properties (defined as mCRL2 µ-calculus formulas) of
session typing contexts. The procedure can be inferred from the
source code
of mcrl2/Property.scala:
-
define a new object MyProperty
that extends the abstract
class Property:
case object MyProperty extends Property(descr, filename, shortName)
where:
-
descr is a human-readable description;
-
filename is the filename of an
mCRL2 formula file (minus its
.mcf extension).
This name is also used to reference the new property by the
mpstk verify command line tool;
-
shortName is a shorthand
used, e.g., in the headers of tables and CSV files;
-
add MyProperty to the
set Properties.all;
-
add the file filename.mcf of the new property
the program resources
directory.
The missing part in the procedure above is how to actually write
the filename.mcf file, so that it can be
correctly used to verify the mCRL2 process specifications
generated
by mcrl2/Spec.scala.
To do it, it is necessary to know
how typing contexts are encoded in mCRL2.
Encoding session typing contexts in mCRL2
NOTE: this section uses some formal notation
defined in the companion paper, and assumes that readers have
some familiarity with the mCRL2 model checker.
Overview
Take a typing context Γ. In a nutshell, the goal of the mCRL2
encoding is to:
-
turn each entry s[p]:T ∈ Γ into a sequential mCRL2
process, that performs input/output actions according to
Definition 2.8 (rules [Γ-&] and [Γ-⊕]). In particular,
mCRL2's choice operator “+”
should model external/internal choices;
-
then, compose the sequential processes above in parallel, to
model the communications of Γ (Definition 2.8, rule [Γ-Comm]).
In particular, the mCRL2's parallel composition operator
“||”, together with
“allow”/“comm”,
should model synchronisation of inputs/outputs with
matching labels/payloads.
Structure of autogenerated mCRL2 specifications
To achieve the above goal, mpstk
converts a typing context Γ (internally represented as
a Context
instance) into a mCRL2 process specification (internally
represented as
a Spec
instance) consisting of three parts:
-
a fixed preamble, available in the
file mpst-preamble.mcrl2.
It defines:
-
various mCRL2 sorts that correspond to the syntax of
multiparty session
types: Session,
Role,
Message,
Payload (for details on the
handling of payloads, see below);
-
actions i / o
/ t (for “tau”), that
correspond, respectively, to the input / output /
communication labels of Definition 2.8 in the companion paper
(with a minor difference: the encoded t
actions do not discard the payload type);
-
an autogenerated mCRL2 process called
“context”,
that is the actual typing context encoding.
The process “context”,
in turn, uses other autogenerated process definitions:
-
one process for each entry s[p]:T ∈ Γ. Such processes use
the i
/ o actions defined in the
preamble, and the choice operator
“+” to model
branching/selection session types. Such processes are
composed in parallel in the definition of
“context”;
-
more process definitions to model the recursive sub-terms
(if any) of each entry s[p]:T ∈ Γ.
-
a fixed initial process declaration,
available in the file
mpst-init.mcrl2.
It declares that “context”
(i.e., the mCRL2-encoded session typing context
defined above)
is the initial mCRL2 process that is verified against
µ-calculus formulas.
In particular, the initial process declaration uses the operators
“allow” / “comm”
to specify
that i/o
actions synchronise by producing t
actions.
NOTE: the encoding above is purposedly
designed with a fixed preamble. The reason is that, by
using the generic sorts and actions defined
in mpst-preamble.mcrl2,
one can develop generic µ-calculus formulas, that can be used to
verify any (encoded) session typing context
— without depending on the actual sessions, roles, message labels, and
payloads used therein. This feature is exploited in
the µ-calculus formulas provided
by mpstk,
and can be leveraged to extend the tool.
The encoding in practice
To better grasp the explanation above, it is possible to inspect
the results of the mCRL2 encoding, by using
the --keep-temp option
of mpstk verify. E.g., by executing:
./bin/mpstk verify --keep-temp examples/oauth2.global
mpstk will not erase its
temporary working directory, and will print its path.
If such a temporary directory
is <DIR>, then the autogenerated
file <DIR>/context.mcrl2
contains various comments that show how the initial global type is
transformed throughout the encoding, and what part of the
multiparty protocol corresponds to each autogenerated mCRL2 process.
The temporary directory also contains other autogenerated
mCRL2 files (with the typical extensions, e.g.,
.lps,
.pbes, .lts):
they can be used to manually invoke the mCRL2 tools.
For more insight, it is also possible to use
the --debug option
of mpstk verify: it logs each use
of the mCRL2 tools on the autogenerated files.
A note on subtyping and message payloads
The explanation above skims over a
subtle, but crucial, detail:
-
in Definition 2.8 of the companion paper, the communication rule
[Γ-Comm] checks whether the payload type being sent
is subtype of the payload type expected by the
recipient;
-
in the mCRL2 encoding, payload types are represented with
the Payload sort, used as part of
i/o
actions...
-
...but when synchronising on such actions, and
yielding t actions, mCRL2 can only
compare Payloads for equality, and
cannot check subtyping — i.e., the resulting semantics is much
more restrictive than Definition 2.8!
To overcome this limitation, mpstk
performs some syntactic pre-processing of typing contexts, before
encoding them in mCRL2.
For example, assume
T⩽S, and consider the typing context
Γ = s[p]:q⊕m(T).T′, s[q]:p&m(S).S′.
Its mCRL2 encoding must model the reduction
Γ → s[p]:T′,s[q]:S′,
as in Definition 2.8.
To this purpose, mpstk pre-processes
Γ as follows:
-
Γ is initially represented as
a Context
instance;
-
mpstk collects all outputs that a
role r might send to another role r′. In this
example, p might send a singleton set of messages
M = { m(T) } to role q;
-
then, Γ is converted into a
raw Context
instance. The difference is that, unlike
Definition 2.4 in the companion paper, the session types in
“raw Γ” can have internal/external choices with
duplicated message labels;
-
then, mpstk rewrites
the “raw Γ” as follows:
-
it checks whether q's type contains some external
choice that might receive a message m(S)
from p;
-
if so, it checks whether the potential outputs of p
(i.e., the set M above)
include some
message m(T) such that T⩽S
(this is why mpstk
implements the
session subtyping algorithm);
-
if so, mpstk extends q's
external choice with a new option m(T), and the
same continuation of the original branch m(S)
(this is implemented in
raw.MPST.addSubBranches());
In this example, the original Γ
above is rewritten as
Γ′ = s[p]:q⊕m(T).T′, s[q]:p&{m(S).S′,m(T).S′}
(notice the new branch of s[q]).
-
finally, the rewritten typing context Γ′ is encoded in
mCRL2, as explained above. Now,
mCRL2 can model synchronisation by simply checking whether an
output action m(T) from p to q is
matched by an equal input action m(T)
by q from p. This models the typing context
reduction
Γ′ → s[p]:T′,s[q]:S′,
thus implementing Definition 2.8 as desired.
This explanation can be seen in practice, by executing, e.g.:
./bin/mpstk verify --keep-temp examples/payload-subtype.ctx
and inspecting the autogenerated file
context.mcrl2,
as illustrated above.
A note on non-tail-recursive types
In the companion paper, Example 5.11 (case ΓC)
shows a non-tail-recursive session type
μ(t)q⊕m(t).end, where the recursion variable t
occurs as payload of the message m. Such types are
troublesome (and usually unsupported) in classic session types
works (c.f. related work in the companion paper) — but they are
seamlessly supported in the new theory
behind mpstk.
To translate such non-tail-recursive types and typing contexts
into mCRL2 specifications, mpstk
proceeds in two steps:
-
it unfolds the message payloads, ensuring that
they have no free variables. This transformation is
provided
by the method MPST.unfoldPayloads;
e.g., the method unfolds the type μ(t)q⊕m(t).end above into
μ(t)q⊕m(μ(t')q⊕m(t').end).end
-
then, mpstk performs the encoding as
described above. The unfolded
payload is handled transparently, by the same principles that handle
the subtyping of message payloads.
This explanation can be seen in practice, by executing, e.g.:
./bin/mpstk verify --keep-temp examples/popl19-ex5.11-c.ctx
and inspecting the autogenerated file
context.mcrl2,
as illustrated above.
mpstk shares some goals and features
with Scribble, the first tool
using the theory of session types to implement protocol
specification and verification.
However, mpstk ha a fundamental design
difference: it is a research tool that strictly adheres to the
new, generalised session types theory introduced in the companion
POPL'19 paper. Scribble, instead, stems from the classic
multiparty session types theory, and adds various extensions and
variations on top of it, mainly for the purpose of automatic code
generation (that mpstk does not
address).
This fundamental difference has two consequences:
-
mpstk can verify multiparty protocols
expressed as typing contexts (.ctx
file format); as a bonus, it can also verify global types
(.global file format), by projecting
them. Scribble, instead, has the opposite design: it is centred
on global types, and projections (as in the classic multiparty
session types theory). Therefore, it is not suited for verifying
protocols that cannot be projected from global types;
-
in particular, mpstk can seamlessly
verify higher-order and
non-tail-recursive types, that are not supported by
Scribble.
TODOs and future work
-
mCRL2 201808.0 has a new feature: a new solver
(pbessolve) that can
generate
counter-examples when a specification does not satisfy a
given µ-calculus formula. With some work, this feature can be
exploited. When a typing context does not satisfy a
property, mpstk could:
-
use pbessolve to generate
the corresponding counter-example — e.g., as a labelled
transition system;
-
prettify the counter-example, by translating its labels (that
are produced by the mCRL2 encoding)
back into the originating typing context labels (c.f.
Definition 2.8 of the companion paper);
-
let mpstk users visualise the
prettified counter-example.
This would help users understand why a multiparty protocol (expressed as a
global type, or typing context) does not satisfy a certain
property.
-
Make mCRL2 file generation and verification more efficient,
by reusing temporary directories and files
across Spec
instances.
-
Improve error messages for (some cases of)
mpstk project.
-
Merge the tools under a single Scala application,
using picocli's
subcommands.
For questions and enquiries, you can contact
the mpstk author:
Alceste Scalas
<alceste (dot) scalas (at) imperial (dot) ac (dot) uk>