SessionTyped Concurrent Contracts
Abstract
In sequential languages, dynamic contracts are usually expressed as boolean functions without externally observable effects, written within the language. We propose an analogous notion of concurrent contracts for languages with sessiontyped messagepassing concurrency. Concurrent contracts are partial identity processes that monitor the bidirectional communication along channels and raise an alarm if a contract is violated. Concurrent contracts are sessiontyped in the usual way and must also satisfy a transparency requirement, which guarantees that terminating compliant programs with and without the contracts are observationally equivalent. We illustrate concurrent contracts with several examples. We also show how to generate contracts from a refinement sessiontype system and show that the resulting monitors are redundant for programs that are welltyped.
Keywords
Contracts Session types Monitors1 Introduction
Contracts, specifying the conditions under which software components can safely interact, have been used for ensuring key properties of programs for decades. Recently, contracts for distributed processes have been studied in the context of session types [15, 17]. These contracts can enforce the communication protocols, specified as session types, between processes. In this setting, we can assign each channel a monitor for detecting whether messages observed along the channel adhere to the prescribed session type. The monitor can then detect any deviant behavior the processes exhibit and trigger alarms. However, contracts based solely on session types are inherently limited in their expressive power. Many contracts that we would like to enforce cannot even be stated using session types alone. As a simple example, consider a “factorization service” which may be sent a (possibly large) integer x and is supposed to respond with a list of prime factors. Session types can only express that the request is an integer and the response is a list of integers, which is insufficient.
In this paper, we show that by generalizing the class of monitors beyond those derived from session types, we can enforce, for example, that multiplying the numbers in the response yields the original integer x. This paper focuses on monitoring more expressive contracts, specifically those that cannot be expressed with session types, or even refinement types.
To handle these contracts, we have designed a model where our monitors execute as transparent processes alongside the computation. They are able to maintain internal state which allows us to check complex properties. These monitoring processes act as partial identities, which do not affect the computation except possibly raising an alarm, and merely observe the messages flowing through the system. They then perform whatever computation is needed, for example, they can compute the product of the factors, to determine whether the messages are consistent with the contract. If the message is not consistent, they stop the computation and blame the process responsible for the mistake. To show that our contracts subsume refinementbased contracts, we encode refinement types in our model by translating refinements into monitors. This encoding is useful because we can show a blame (safety) theorem stating that monitors that enforce a less precise refinement type than the type of the process being monitored will not raise alarms. Unfortunately, the blame theory for the general model is challenging because the contracts cannot be expressed as types.

A novel approach to contract checking via partialidentity monitors

A method for verifying that monitors are partial identities, and a proof that the method is correct

Examples showing the breadth of contracts that our monitors can enforce

A translation from refinement types to our monitoring processes and a blame theorem for this fragment
The rest of this paper is organized as follows. We first review the background on session types in Sect. 2. Next, we show a range of example contracts in Sect. 3. In Sect. 4, we show how to check that a monitor process is a partial identity and prove the method correct. We then show how we can encode refinements in our system in Sect. 5. We discuss related work in Sect. 6. Due to space constraints, we only present the key theorems. Detailed proofs can be found in our companion technical report [12].
2 Session Types
In order to define the operational semantics rigorously, we use multiset rewriting [6]. The configuration of executing processes is described as a collection \(\mathcal {C}\) of propositions \(\mathsf {proc}(c, P)\) (process P is executing, providing along c) and \(\mathsf {msg}(c, M)\) (message M is sent along c). All the channels c provided by processes and messages in a configuration must be distinct.
We consider each class of session type constructors, describing their process expression, typing, and asynchronous operational semantics. The linear logical semantics can be recovered by ignoring the process expressions and channels.
Internal and External Choice. Even though we distinguish a provider and its client, this distinction is orthogonal to the direction of communication: both may either send or receive along a common private channel. Session typing guarantees that both sides will always agree on the direction and kind of message that is sent or received, so our situation corresponds to socalled binary session types.
The most popular formalization of equirecursive types is to introduce an explicit \(\mu \)constructor. For example, \( \mathsf {list} = \mu \alpha .\, {\oplus }\{\ \mathsf {cons} : \exists n{:}\mathsf {int}.\, \alpha , \mathsf {nil} : \mathbf {1}\ \} \) with rules unrolling the type \(\mu \alpha .\, A\) to \([(\mu \alpha .\, A)/\alpha ]A\). An alternative (see, for example, Balzers and Pfenning 2017 [3]) is to use an explicit definition just as we stated, for example, \(\mathsf {list}\) and \(\mathsf {bag}\), and consider the lefthand side equal to the righthand side in our discourse. In typing, this works without a hitch. When we consider subtyping explicitly, we need to make sure we view inference systems on types as being defined coinductively. Since a coinductively defined judgment essentially expresses the absence of a counterexample, this is exactly what we need for the operational properties like progress, preservation, or absence of blame. We therefore adopt this view.
One more quick shorthand used in the examples: a tailcall \(c \leftarrow p\; \overline{e} \leftarrow \overline{d}\) in the definition of a process that provides along c is expanded into \(c' \leftarrow p\; \overline{e} \leftarrow \overline{d} \mathrel {;}c \leftarrow c'\) for a fresh \(c'\). Depending on how forwarding is implemented, however, it may be much more efficient [13].
3 Contract Examples
In this section, we present monitoring processes that can enforce a variety of contracts. The examples will mainly use lists as defined in the previous section. Our monitors are transparent, that is, they do not change the computation. We accomplish this by making them act as partial identities (described in more detail in Sect. 4). Therefore, any monitor that enforces a contract on a list must peel off each layer of the type one step at a time (by sending or receiving over the channel as dictated by the type), perform the required checks on values or labels, and then reconstruct the original type (again, by sending or receiving as appropriate).
Our monitors can also exploit information that is contained in the labels in the external and internal choices. The \(\mathtt {empty}\) process checks whether the list b is empty and aborts if b sends the label \(\mathtt {cons}\). Similarly, the \(\mathtt {nempty}\) monitor checks whether the list b is not empty and aborts if b sends the label \(\mathtt {nil}\). These two monitors can then be used by a process that zips two lists and aborts if they are of different lengths. These two monitors enforce the refinements \(\{\mathtt{nil}\} \subseteq \{\mathtt{nil}, \mathtt{cons}\}\) and \(\{\mathtt{cons}\} \subseteq \{\mathtt{nil}, \mathsf {cons}\}\). We discuss how to generate monitors from refinement types in more detail in Sect. 5.
Monitors with Internal State. We now move beyond refinement contracts, and model contracts that have to maintain some internal state (Fig. 2).
If the list is empty, there is no bound to check, so no contract failure can happen. If the list is nonempty, we check to see if a bound has already been set. If not, we set the bound to be the first received element. If there is already a bound in place, then we check if the received element is greater or equal to the bound. If it is not, then the list must be unsorted, so we abort with a contract failure. Note that the output list m is the same as the input list n because every element that we examine is then passed along unchanged to m.
We can use the \(\mathtt {ascending}\) monitor to verify that the output list of a sorting procedure is in sorted order. To take the example one step further, we can verify that the elements in the output list are in fact a permutation of the elements in the input list of the sorting procedure as follows. Using a reasonable hash function, we hash each element as it is sent to the sorting procedure. Our monitor then keeps track of a running total of the sum of the hashes, and as elements are received from the sorting procedure, it computes their hash and subtracts it from the total. After all of the elements are received, we check that the total is 0 – if it is, with high probability, the two lists are permutations of each other. This example is an instance of result checking, inspired by Wasserman and Blum [26]. The monitor encoding is straightforward and omitted from the paper.
Mapper. Finally, we can also define monitors that check higherorder contracts, such as a contract for a mapping function (Fig. 3). Consider the mapper which takes an integer and doubles it, and a function \(\mathtt {map}\) that applies this mapper to a list of integers to produce a new list of integers. We can see that any integer that the mapper has produced will be strictly larger than the original integer, assuming the original integer is positive. In order to monitor this contract, it makes sense to impose a contract on the mapper itself. This \(\mathtt {mapper\_mon}\) process enforces both the precondition, that the original integer is positive, and the postcondition, that the resulting integer is greater than the original. We can now run the monitor on the mapper, in the \(\mathtt {map}\) process, before applying the mapper to the list l.
4 Monitors as Partial Identity Processes
In the literature on contracts, they are often depicted as guards on values sent to and returned from functions. In our case, they really are processes that monitor messagepassing communications between processes. For us, a central property of contracts is that a program may be executed with or without contract checking and, unless an alarm is raised, the observable outcome should be the same. This means that contract monitors should be partial identity processes passing messages back and forth along channels while testing properties of the messages.
This may seem very limiting at first, but sessiontyped processes can maintain local state. For example, consider the functional notion of a dependent contract, where the contract on the result of a function depends on its input. Here, a function would be implemented by a process to which you send the arguments and which sends back the return value along the same channel. Therefore, a monitor can remember any (nonlinear) “argument values” and use them to validate the “result value”. Similarly, when a list is sent element by element, properties that can be easily checked include constraints on its length, or whether it is in ascending order. Moreover, local state can include additional (private) concurrent processes.
This raises a second question: how can we guarantee that a monitor really is a partial identity? The criterion should be general enough to allow us to naturally express the contracts from a wide range of examples. A key constraint is that contracts are expressed as sessiontyped processes, just like functional contracts should be expressed within the functional language, or object contracts within the object oriented language, etc.
The purpose of this section is to present and prove the correctness of a criterion on sessiontyped processes that guarantees that they are observationally equivalent to partial identity processes. All the contracts in this paper can be verified to be partial identities under our definition.
4.1 Buffering Values
4.2 Rule Summary
4.3 Spawning New Processes
In actual programs, we mostly use cut \(x \leftarrow P \mathrel {;}Q\) in the form \(x \leftarrow p\; \overline{e} \leftarrow \overline{d} \mathrel {;}Q\) where p is a defined process. The rules are completely analogous, except that for those rules that require splitting a context in the conclusion, the arguments \(\overline{d}\) will provide the split for us. When a new submonitor is invoked in this way, we remember and eventually check that the process p must also be a partial identity process, unless we are already checking it. This has the effect that recursively defined monitors with proper recursive calls are in fact allowed. This is important, because monitors for recursive types usually have a recursive structure. An illustration of this can be seen in \(\mathsf {pos}\) in Fig. 1.
4.4 Transparency
 1.
If \(\varGamma ' \vdash \mathsf {msg}^+(c, P) :\,\!: \varGamma \) then \(\varGamma ' \vdash (\mathsf {msg}^+(c, P), \mathcal {C}) \sim (\mathsf {msg}^+(c, P), \mathcal {D}) :\,\!: \varDelta \).
 2.
If \(\varDelta \vdash \mathsf {msg}^(c, P) :\,\!: \varDelta '\) then \(\varGamma \vdash (\mathcal {C}, \mathsf {msg}^(c,P)) \sim (\mathcal {D}, \mathsf {msg}^(c,P)) :\,\!: \varDelta '\).
 3.
If \(\mathcal {C}= (\mathcal {C}', \mathsf {msg}^+(c,P))\) with \(\varGamma \vdash \mathcal {C}' :\,\!: \varDelta _1'\) and \(\varDelta _1' \vdash \mathsf {msg}^+(c,P) :\,\!: \varDelta \)
and \(\mathcal {D}= (\mathcal {D}', \mathsf {msg}^+(c,Q))\) with \(\varGamma \vdash \mathcal {D}' :\,\!: \varDelta _2'\) and \(\varDelta _2' \vdash \mathsf {msg}^+(c,Q) :\,\!: \varDelta \)
then \(\varDelta _1' = \varDelta _2' = \varDelta '\) and \(P = Q\) and \(\varGamma \vdash \mathcal {C}' \sim \mathcal {D}' :\,\!: \varDelta '\).
 4.
If \(\mathcal {C}= (\mathsf {msg}^(c,P), \mathcal {C}')\) with \(\varGamma \vdash \mathsf {msg}^(c,P) :\,\!: \varGamma _1'\) and \(\varGamma _1' \vdash \mathcal {C}' :\,\!: \varDelta \)
and \(\mathcal {D}= (\mathsf {msg}^(c,Q), \mathcal {D}')\) with \(\varGamma \vdash \mathsf {msg}^(c,Q):\,\!: \varGamma _2'\) and \(\varGamma _2' \vdash \mathcal {D}' :\,\!: \varDelta \)
then \(\varGamma _1' = \varGamma _2' = \varGamma '\) and \(P = Q\) and \(\varGamma ' \vdash \mathcal {C}' \sim \mathcal {D}' :\,\!: \varDelta \).
 5.
If \(\mathcal {C}\longrightarrow \mathcal {C}'\) then \(\varGamma \vdash \mathcal {C}' \sim \mathcal {D}:\,\!: \varDelta \).
 6.
If \(\mathcal {D}\longrightarrow \mathcal {D}'\) then \(\varGamma \vdash \mathcal {C}\sim \mathcal {D}' :\,\!: \varDelta \).
Clauses (1) and (2) correspond to absorbing a message into a configuration, which may later be received by a process according to clauses (5) and (6).
Clauses (3) and (4) correspond to observing messages, either by a client (clause (3)) or provider (clause (4)).
In clause (3) we take advantage of the property that a new continuation channel in the message P (one that does not appear already in \(\varGamma \)) is always chosen fresh when created, so we can consistently (and silently) rename it in \(\mathcal {C}'\), \(\varDelta _1'\), and P (and \(\mathcal {D}'\), \(\varDelta _2'\), and Q, respectively). This slight of hand allows us to match up the context and messages exactly. An analogous remark applies to clause (4). A more formal description would match up the contexts and messages modulo two renaming substitution which allow us to leave \(\varGamma \) and \(\varDelta \) fixed.
Clauses (5) and (6) make sense because a transition never changes the interface to a configuration, except when executing a forwarding \(\mathsf {proc}(a, a \leftarrow b)\) which substitutes b for a in the remaining configuration. We can absorb this renaming into the renaming substitution. Cut creates a new channel, which remains internal since it is linear and will have one provider and one client within the new configuration. Unfortunately, our notation is already somewhat unwieldy and carrying additional renaming substitutions further obscures matters. We therefore omit them in this presentation.
We now need to define a relation \(\sim _M\) such that (a) it satisfies the closure conditions of \(\sim \) and is therefore an observational equivalence, and (b) allows us to conclude that monitors satisfying our judgment are partial identities. Unfortunately, the theorem is rather complex, so we will walk the reader through a sequence of generalizations that account for various phenomena.
 (\(1^+\))

If \((y:A^+) \mathrel {;}\cdot \mathrel {;}\cdot \vdash P :\,\!: (x:A^+)[\;]\)
then \(y : A^+ \vdash \mathsf {proc}(x, x \leftarrow y) \sim _M P :\,\!: (x : A^+)\)
 (\(1^\))

If \([\;](y:A^) \mathrel {;}\cdot \mathrel {;}\cdot \vdash P :\,\!: (x:A^)\)
then \(y:A^ \vdash \mathsf {proc}(x, x\leftarrow y) \sim _M P :\,\!: (x : A^)\)
 (\(2^+\))

If \((y {:} B^+) \mathrel {;}\cdot \mathrel {;}\cdot \mathrel {;}\cdot \vdash P :\,\!: (x {:} A^+)[\langle \!\langle \mathcal {E}\rangle \!\rangle ]\) then \(y:B^+ \vdash \mathcal {E}\sim _M \mathsf {proc}(x,P) :\,\!: (x : A^+)\).
 (\(2^\))

If \([\langle \!\langle \mathcal {E}\rangle \!\rangle ](y{:}B^) \cdot \mathrel {;}\cdot \mathrel {;}\cdot \vdash P :\,\!: (x{:}A^)\) then \(y{:}B^ \vdash \mathcal {E}\sim _M \mathsf {proc}(x,P) :\,\!: (x{ :} A^)\).
 (\(3^+\))

If \(\omega \mathrel {;}\cdot \mathrel {;}\cdot \mathrel {;}\cdot \vdash P :\,\!: (x {:} A^+)[\langle \!\langle \mathcal {E}\rangle \!\rangle ]\) then \(\omega \vdash \mathcal {E}\sim _M \mathsf {proc}(x,P) :\,\!: (x {:} A^+)\).
 (\(3^\))

If \([\langle \!\langle \mathcal {E}\rangle \!\rangle ](y{:}B^) \mathrel {;}\cdot \mathrel {;}\cdot \mathrel {;}\cdot \vdash P :\,\!: (x{:}A)\) then \(y{:}B^ \vdash \mathcal {E}\sim _M \mathsf {proc}(x,P) :\,\!: (x {:}x A)\).
 (\(4^+\))

If \(\omega \mathrel {;}\cdot \mathrel {;}\cdot \mathrel {;}\varDelta \vdash P :\,\!: [\langle \!\langle \mathcal {E}\rangle \!\rangle ](x : A^+)\) and \(\cdot \vdash \mathcal {D}:\,\!: \varDelta \) then \(\omega \vdash \mathcal {E}\sim _M \mathcal {D}, \mathsf {proc}(x,P) :\,\!: [q](x : A^+)\).
 (\(4^\))

If \([\langle \!\langle \mathcal {E}\rangle \!\rangle ](y:B^) \mathrel {;}\cdot \mathrel {;}\cdot \mathrel {;}\varDelta \vdash P :\,\!: (x:A)\) and \(\cdot \vdash \mathcal {D}:\,\!: \varDelta \) then \(\varGamma , y:B^ \vdash \mathcal {E}\sim _M \mathcal {D}, \mathsf {proc}(x,P) :\,\!: (x : A)\).
 (\(5^+\))

If \(\omega \mathrel {;}\varPsi \mathrel {;}\cdot \mathrel {;}\varDelta \vdash P :\,\!: [q](x : A^+)\) and \(\sigma : \varPsi \) and \(q[\sigma ] = \langle \!\langle \mathcal {E}\rangle \!\rangle \) and \(\cdot \vdash \mathcal {D}:\,\!: \varDelta [\sigma ]\) then \(\omega [\sigma ] \vdash \mathcal {E}\sim _M \mathcal {D}, \mathsf {proc}(x,P[\sigma ]) :\,\!: (x : A^+[\sigma ])\).
 (\(5^\))

If \([q](y:B^) \mathrel {;}\varPsi \mathrel {;}\cdot \mathrel {;}\varDelta \vdash P :\,\!: (x:A)\) and \(\sigma : \varPsi \) and \(q[\sigma ] = \mathcal {E}\) and \(\cdot \vdash \mathcal {D}:\,\!: \varDelta [\sigma ]\) then \(y:B^[\sigma ] \vdash \mathcal {E}\sim _M \mathcal {D}, \mathsf {proc}(x,P[\sigma ]) :\,\!: (x : A[\sigma ])\).
 (6)

If \(\omega \vdash \mathcal {E}_1 \sim _M \mathcal {D}_1 :\,\!: (z : C)\) and \((z : C) \vdash \mathcal {E}_2 \sim _M \mathcal {D}_2 :\,\!: (x : A)\) then \(\omega \vdash (\mathcal {E}_1,\mathcal {E}_2) \sim _M (\mathcal {D}_1,\mathcal {D}_2) :\,\!: (x : A)\).
 (\(7^+\))

If \(\omega \mathrel {;}\varPsi \mathrel {;}\varGamma \mathrel {;}\varDelta \vdash P :\,\!: [q](x : A^+)\) and \(\sigma : \varPsi \) and \(q[\sigma ] = \langle \!\langle \mathcal {E}\rangle \!\rangle \) and \(\cdot \vdash \mathcal {D}:\,\!: \varDelta [\sigma ]\) then \(\varGamma [\sigma ], \omega [\sigma ] \vdash \mathcal {E}\sim _M \mathcal {D}, \mathsf {proc}(x,P[\sigma ]) :\,\!: (x : A^+[\sigma ])\).
 (\(7^\))

If \([q](y:B^) \mathrel {;}\varPsi \mathrel {;}\varGamma \mathrel {;}\varDelta \vdash P :\,\!: (x:A)\) and \(\sigma : \varPsi \) and \(q[\sigma ] = \mathcal {E}\) and \(\cdot \vdash \mathcal {D}:\,\!: \varDelta [\sigma ]\) then \(\varGamma [\sigma ], y:B^[\sigma ] \vdash \mathcal {E}\sim _M \mathcal {D}, \mathsf {proc}(x,P[\sigma ]) :\,\!: (x : A[\sigma ])\).
 (8)

If \(\varGamma \vdash \mathcal {E}\sim _M \mathcal {D}:\,\!: \varDelta \) then \((\varGamma ', \varGamma ) \vdash \mathcal {E}\sim _M \mathcal {D}:\,\!: (\varGamma ', \varDelta )\).
 (9)

If \(\varGamma _1 \vdash \mathcal {E}_1 \sim _M \mathcal {D}_1 :\,\!: \varGamma _2\) and \(\varGamma _2 \vdash \mathcal {E}_2 \sim _M \mathcal {D}_2 :\,\!: \varGamma _3\) then \(\varGamma _1 \vdash (\mathcal {E}_1,\mathcal {E}_2) \sim _M (\mathcal {D}_1,\mathcal {D}_2) :\,\!: \varGamma _3\).
At this point we can state the main theorem regarding monitors.
Theorem 1
If \(\varGamma \vdash \mathcal {E}\sim _M \mathcal {D}:\,\!: \varDelta \) according to properties \((7^+), (7^), (8), and (9)\) then \(\varGamma \vdash \mathcal {E}\sim \mathcal {D}:\,\!: \varDelta \).
Proof
By closure under conditions 1–6 in the definition of \(\sim \).
By applying it as in equations (\(1^+\)) and (\(1^\)), generalized to include value variables as in (\(5^+\)) and (\(5^\)) we obtain:
Corollary 1
If \([\; ](b : A^) \mathrel {;}\varPsi \vdash P :\,\!: (a : A^)\) or \((b : A^+) \mathrel {;}\varPsi \vdash P :\,\!: [\;](a : A^+)\) then P is a partial identity process.
5 Refinements as Contracts
In this section we show how to check refinement types dynamically using our contracts. We encode refinements as type casts, which allows processes to remain welltyped with respect to the nonrefinement type system (Sect. 2). These casts are translated at run time to monitors that validate whether the cast expresses an appropriate refinement. If so, the monitors behave as identity processes; otherwise, they raise an alarm and abort. For refinement contracts, we can prove a safety theorem, analogous to the classic “Welltyped Programs Can’t be Blamed” [25], stating that if a monitor enforces a contract that casts from type A to type B, where A is a subtype of B, then this monitor will never raise an alarm.
5.1 Syntax and Typing Rules
5.2 Translation to Monitors
At run time, casts are translated into monitoring processes. A cast \(a\leftarrow \langle A \Leftarrow B \rangle ^{\rho }\ b\) is implemented as a monitor. This monitor ensures that the process that offers a service on channel b behaves according to the prescribed type A. Because of the typing rules, we are assured that channel b must adhere to the type B.
Figure 4 is a summary of all the translation rules, except recursive types. The translation is of the form: \([\![\langle A \Leftarrow B \rangle ^{\rho }]\!]_{a, b} = P\), where A, B are types; the channels a and b are the offering channel and monitoring channel (respectively) for the resulting monitoring process P; and \(\rho \) is a label of the monitor (i.e., the contract).
The translation is defined inductively over the structure of the types. The \(\mathsf {tensor}\) rule generates a process that first receives a channel (x) from the channel being monitored (b). It then spawns a new monitor (denoted by the \(\mathsf {@monitor}\) keyword) to monitor channel x, making sure that it behaves as type \(A_1\), and passes the new monitor’s offering channel y to channel a. Finally, the monitor continues to monitor b to make sure that it behaves as type \(A_2\). The \(\mathsf {lolli}\) rule is similar to the \(\mathsf {tensor}\) rule, except that the monitor first receives a channel from its offering channel. Similar to the higherorder function case, the argument position is contravariant, so the newly spawned monitor checks that the received channel behaves as type \(B_1\). The \(\mathsf {exists}\) rule generates a process that first receives a value from the channel b, then checks the boolean condition e to validate the contract. The \(\mathsf {forall}\) rule is similar, except the argument position is contravariant, so the boolean expression \(e'\) is checked on the offering channel a. The \(\mathsf {with}\) rule generates a process that checks that all of the external choices promised by the type Open image in new window are offered by the process being monitored. If a label in the set I is not implemented, then the monitor aborts with the label \(\rho \). The \(\mathsf {plus}\) rule requires that, for internal choices, the monitor checks that the monitored process only offers choices within the labels in the set \({\oplus }\{\ell : A_\ell \}_{\ell \in I}\).
For ease of explanation, we omit details for translating casts involving recursive types. Briefly, these casts are translated into recursive processes. For each pair of compatible recursive types A and B, we generate a unique monitor name f and record its type \(f:\{A \leftarrow B\}\) in a context \(\varPsi \). The translation algorithm needs to take additional arguments, including \(\varPsi \) to generate and invoke the appropriate recursive process when needed. For instance, when generating the monitor process for \(f:\{\mathsf {list}\leftarrow \mathsf {list}\}\), we follow the rule for translating internal choices. For \([\![\langle \mathsf {list} \Leftarrow \mathsf {list} \rangle ^{\rho }]\!]_{y, x}\) we apply the \(\mathsf {cons}\) case in the translation to get \(@\mathsf {monitor}\ y\leftarrow \ f\ \leftarrow x\).
5.3 Metatheory
We prove two formal properties of castbased monitors: safety and transparency.
Theorem 2
(Monitors are welltyped). Let \(\varPsi \) be the context containing the type bindings of all recursive processes.
 1.
\(\varPsi \mathrel {;}b:B \vdash _T [\![\langle A \Leftarrow B \rangle ^{\rho }]\!]_{a,b}^\varPsi \) : : (a : A).
 2.
If \(B \le A\), then \( \varPsi \mathrel {;}b:B \vdash _S [\![\langle A \Leftarrow B \rangle ^{\rho }]\!]_{a,b}^\varPsi :\,\!: (a : A)\).
Proof
The proof is by induction over the monitor translation rules. For 2, we need to use the subtyping relation to show that (1) for the internal and external choice cases, no branches that include \(\mathsf {abort}\) are generated; and (2) for the forall and exists cases, the assert never fails (i.e., the \(\mathsf {assert\_strong}\) rule applies). \(\square \)
As a corollary, we can show that when executing in a welltyped context, a monitor process translated from a welltyped cast will never raise an alarm.
Corollary 2
(Welltyped casts cannot raise alarms). \(\vdash \mathcal {C}:\,\!: b:B\) and \(B \le A\) implies Open image in new window .
Finally, we prove that monitors translated from casts are partial identify processes.
Theorem 3
(Casts are transparent).
\(b:B \vdash \mathsf {proc}(b, a\leftarrow b)\sim \mathsf {proc}(a, [\![\langle A \Leftarrow B \rangle ^{\rho }]\!]_{a,b}) :\,\!: (a: A)\).
Proof
We just need to show that the translated process passes the partial identity checks. We can show this by induction over the translation rules and by applying the rules in Sect. 4. We note that rules in Sect. 4 only consider identical types; however, our casts only cast between two compatible types. Therefore, we can lift A and B to their super types (i.e., insert abort cases for mismatched labels), and then apply the checking rules. This does not change the semantics of the monitors.
6 Related Work
There is a rich body of work on higherorder contracts and the correctness of blame assignments in the context of the lambda calculus [2, 7, 8, 10, 16, 24, 25]. The contracts in these papers are mostly based on refinement or dependent types. Our contracts are more expressive than the above, and can encode refinementbased contracts. While our monitors are similar to reference monitors (such as those described by Schneider [19]), they have a few features that are not inherent to reference monitors such as the fact that our monitors are written in the target language. Our monitors are also able to monitor contracts in a higherorder setting by spawning a separate monitor for the sent/received channel.
Disney et al.’s [9] work, which investigates behavioral contracts that enforce temporal properties for modules, is closely related to our work. Our contracts (i.e., session types) also enforce temporal properties; the session types specify the order in which messages are sent and received by the processes. Our contracts can also make use of internal state, as those of Disney et al, but our system is concurrent, while their system does not consider concurrency.
Recently, gradual typing for twoparty sessiontype systems has been developed [14, 20]. Even though this formalism is different from our contracts, the way untyped processes are gradually typed at run time resembles how we monitor type casts. Because of dynamic session types, their system has to keep track of the linear use of channels, which is not needed for our monitors.
Most recently, Melgratti and Padovani have developed chaperone contracts for higherorder session types [17]. Their work is based on a classic interpretation of session types, instead of an intuitionistic one like ours, which means that they do not handle spawning or forwarding processes. While their contracts also inspect messages passed between processes, unlike ours, they cannot model contracts which rely on the monitor making use of internal state (e.g., the parenthesis matching). They proved a blame theorem relying on the notion of locally correct modules, which is a semantic categorization of whether a module satisfies the contract. We did not prove a general blame theorem; instead, we prove a somewhat standard safety theorem for castbased contracts.
The Whip system [27] addresses a similar problem as our prior work [15], but does not use session types. They use a dependent type system to implement a contract monitoring system that can connect services written in different languages. Their system is also higher order, and allows processes that are monitored by Whip to interact with unmonitored processes. While Whip can express dependent contacts, Whip cannot handle stateful contracts. Another distinguishing feature of our monitors is that they are partial identity processes encoded in the same language as the processes to be monitored.
7 Conclusion
We have presented a novel approach for contractchecking for concurrent processes. Our model uses partial identity monitors which are written in the same language as the original processes and execute transparently. We define what it means to be a partial identity monitor and prove our characterization correct. We provide multiple examples of contracts we can monitor including ones that make use of the monitor’s internal state, ones that make use of the idea of probabilistic result checking, and ones that cannot be expressed as dependent or refinement types. We translate contracts in the refinement fragment into monitors, and prove a safety theorem for that fragment.
Notes
Acknowledgment
This research was supported in part by NSF grant CNS1423168 and a Carnegie Mellon University Presidential Fellowship.
References
 1.Acay, C., Pfenning, F.: Intersections and unions of session types. In: Proceedings Eighth Workshop on Intersection Types and Related Systems, ITRS 2016, Porto, Portugal, pp. 4–19, 26 June 2016. https://dx.doi.org/10.4204/EPTCS.242.3MathSciNetCrossRefGoogle Scholar
 2.Ahmed, A., Findler, R.B., Siek, J.G., Wadler, P.: Blame for all. In: 38th ACM SIGPLANSIGACT Symposium on Principles of Programming Languages (POPL 2011) (2011). https://doi.acm.org/10.1145/1570506.1570507
 3.Balzer, S., Pfenning, F.: Manifest sharing with session types. Proc. ACM Program. Lang. 1(ICFP), 37:1–37:29 (2017). https://doi.org/10.1145/3110281CrossRefGoogle Scholar
 4.Caires, L., Pfenning, F.: Session types as intuitionistic linear propositions. In: Gastin, P., Laroussinie, F. (eds.) CONCUR 2010. LNCS, vol. 6269, pp. 222–236. Springer, Heidelberg (2010). https://doi.org/10.1007/9783642153754_16CrossRefGoogle Scholar
 5.Caires, L., Pfenning, F., Toninho, B.: Linear logic propositions as session types. Math. Struct. Comput. Sci. 26(3), 367–423 (2016)MathSciNetCrossRefGoogle Scholar
 6.Cervesato, I., Scedrov, A.: Relating statebased and processbased concurrency through linear logic. Inf. Comput. 207(10), 1044–1077 (2009). https://doi.org/10.1016/j.ic.2008.11.006CrossRefzbMATHGoogle Scholar
 7.Dimoulas, C., Findler, R.B., Flanagan, C., Felleisen, M.: Correct blame for contracts: no more scapegoating. In: Proceedings of the 38th Annual ACM SIGPLANSIGACT Symposium on Principles of Programming Languages, POPL 2011, pp. 215–226. ACM, New York (2011). https://doi.acm.org/10.1145/1926385.1926410
 8.Dimoulas, C., TobinHochstadt, S., Felleisen, M.: Complete monitors for behavioral contracts. In: Seidl, H. (ed.) ESOP 2012. LNCS, vol. 7211, pp. 214–233. Springer, Heidelberg (2012). https://doi.org/10.1007/9783642288692_11CrossRefGoogle Scholar
 9.Disney, T., Flanagan, C., McCarthy, J.: Temporal higherorder contracts. In: 16th ACM SIGPLAN International Conference on Functional Programming (ICFP 2011) (2011). https://doi.acm.org/10.1145/2034773.2034800
 10.Findler, R.B., Felleisen, M.: Contracts for higherorder functions. In: Proceedings of the Seventh ACM SIGPLAN International Conference on Functional Programming, ICFP 2002, pp. 48–59. ACM, New York (2002). https://doi.acm.org/10.1145/581478.581484
 11.Gay, S.J., Hole, M.: Subtyping for session types in the \(\pi \)calculus. Acta Informatica 42(2–3), 191–225 (2005). https://doi.org/10.1007/s002360050177zMathSciNetCrossRefzbMATHGoogle Scholar
 12.Gommerstadt, H., Jia, L., Pfenning, F.: Sessiontyped concurrent contracts. Technical report CMUCyLab17004, CyLab, Carnegie Mellon University, February 2018Google Scholar
 13.Griffith, D.: Polarized Substructural Session Types. Ph.D. thesis, University of Illinois at UrbanaChampaign, April 2016Google Scholar
 14.Igarashi, A., Thiemann, P., Vasconcelos, V.T., Wadler, P.: Gradual session types. Proc. ACM Program. Lang. 1(ICFP), 38:1–38:28 (2017). https://doi.org/10.1145/3110282CrossRefGoogle Scholar
 15.Jia, L., Gommerstadt, H., Pfenning, F.: Monitors and blame assignment for higherorder session types. In: Proceedings of the 43rd Annual ACM SIGPLANSIGACT Symposium on Principles of Programming Languages, POPL 2016, pp. 582–594. ACM, New York (2016). https://doi.acm.org/10.1145/2837614.2837662
 16.Keil, M., Thiemann, P.: Blame assignment for higherorder contracts with intersection and union. In: 20th ACM SIGPLAN International Conference on Functional Programming (ICFP 2015) (2015). https://doi.acm.org/10.1145/2784731.2784737
 17.Melgratti, H., Padovani, L.: Chaperone contracts for higherorder sessions. Proc. ACM Program. Lang. 1(ICFP), 35:1–35:29 (2017). https://doi.org/10.1145/3110279CrossRefGoogle Scholar
 18.Pfenning, F., Griffith, D.: Polarized substructural session types. In: Pitts, A. (ed.) FoSSaCS 2015. LNCS, vol. 9034, pp. 3–22. Springer, Heidelberg (2015). https://doi.org/10.1007/9783662466780_1CrossRefGoogle Scholar
 19.Schneider, F.B.: Enforceable security policies. ACM Trans. Inf. Syst. Secur. 3(1), 30–50 (2000). https://doi.org/10.1145/353323.353382CrossRefGoogle Scholar
 20.Thiemann, P.: Session types with gradual typing. In: Maffei, M., Tuosto, E. (eds.) TGC 2014. LNCS, vol. 8902, pp. 144–158. Springer, Heidelberg (2014). https://doi.org/10.1007/9783662459171_10CrossRefGoogle Scholar
 21.Thiemann, P., Vasconcelos, V.T.: Contextfree session types. In: Proceedings of the 21st ACM SIGPLAN International Conference on Functional Programming, ICFP 2016, pp. 462–475. ACM, New York (2016). https://acm.doi.org/10.4230/LIPIcs.ECOOP.2016.9
 22.Toninho, B.: A Logical Foundation for Sessionbased Concurrent Computation. Ph.D. thesis, Carnegie Mellon University and New University of Lisbon (2015)Google Scholar
 23.Toninho, B., Caires, L., Pfenning, F.: Higherorder processes, functions, and sessions: a monadic integration. In: Felleisen, M., Gardner, P. (eds.) ESOP 2013. LNCS, vol. 7792, pp. 350–369. Springer, Heidelberg (2013). https://doi.org/10.1007/9783642370366_20CrossRefzbMATHGoogle Scholar
 24.Wadler, P.: A complement to blame. In: 1st Summit on Advances in Programming Languages (SNAPL 2015) (2015). https://doi.acm.org/10.4230/LIPIcs.SNAPL.2015.309
 25.Wadler, P., Findler, R.B.: Welltyped programs can’t be blamed. In: Castagna, G. (ed.) ESOP 2009. LNCS, vol. 5502, pp. 1–16. Springer, Heidelberg (2009). https://doi.org/10.1007/9783642005909_1CrossRefGoogle Scholar
 26.Wasserman, H., Blum, M.: Software reliability via runtime resultchecking. J. ACM 44(6), 826–849 (1997). https://doi.org/10.1145/268999.269003MathSciNetCrossRefzbMATHGoogle Scholar
 27.Waye, L., Chong, S., Dimoulas, C.: Whip: higherorder contracts for modern services. Proc. ACM Program. Lang. 1(ICFP), 36:1–36:28 (2017). https://doi.org/10.1145/3110280CrossRefGoogle Scholar
Copyright information
Open Access This chapter is licensed under the terms of the Creative Commons Attribution 4.0 International License (http://creativecommons.org/licenses/by/4.0/), which permits use, sharing, adaptation, distribution and reproduction in any medium or format, as long as you give appropriate credit to the original author(s) and the source, provide a link to the Creative Commons license and indicate if changes were made. The images or other third party material in this book are included in the book's Creative Commons license, unless indicated otherwise in a credit line to the material. If material is not included in the book's Creative Commons license and your intended use is not permitted by statutory regulation or exceeds the permitted use, you will need to obtain permission directly from the copyright holder.