Communication-Safe Web Programming in Typescript with Routed Multiparty Session Types
Communication-Safe Web Programming in TypeScript with Routed Multiparty Session Types
Anson Miu Francisco Ferreira Imperial College London and Bloomberg Imperial College London United Kingdom United Kingdom Nobuko Yoshida Fangyi Zhou Imperial College London Imperial College London United Kingdom United Kingdom
Abstract ACM Reference Format: Modern web programming involves coordinating interac- Anson Miu, Francisco Ferreira, Nobuko Yoshida, and Fangyi Zhou. tions between browser clients and a server. Typically, the 2021. Communication-Safe Web Programming in TypeScript with Routed Multiparty Session Types. In Proceedings of the 30th ACM interactions in web-based distributed systems are informally SIGPLAN International Conference on Compiler Construction (CC ’21), described, making it hard to ensure correctness, especially March 2–3, 2021, Virtual, USA. ACM, New York, NY, USA, 27 pages. communication safety, i.e. all endpoints progress without https://doi.org/10.1145/3446804.3446854 type errors or deadlocks, conforming to a specified protocol. We present STScript, a toolchain that generates TypeScript 1 Introduction APIs for communication-safe web development over Web- Web technology advancements have changed the way peo- Sockets, and RouST, a new session type theory that supports ple use computers. Many services that required standalone multiparty communications with routing mechanisms. applications, such as email, chat, video conferences, or even STScript provides developers with TypeScript APIs gen- games, are now provided in a browser. While the Hypertext erated from a communication protocol specification based Transfer Protocol (HTTP) is widely used for serving web on RouST. The generated APIs build upon TypeScript con- pages, its Request-Response model limits the communication currency practices, complement the event-driven style of patterns — the server may not send data to a client without programming in full-stack web development, and are com- the client first making a request. patible with the Node.js runtime for server-side endpoints The WebSocket Protocol [12] addresses this limitation by and the React.js framework for browser-side endpoints. providing a bi-directional channel between the client and RouST can express multiparty interactions routed via an the server, akin to a Unix socket. Managing the correct usage intermediate participant. It supports peer-to-peer commu- of WebSockets introduces an additional concern in the de- nication between browser-side endpoints by routing com- velopment process, due to a lack of WebSocket testing tools, munication via the server in a way that avoids excessive requiring an (often ad-hoc) specification of the communica- serialisation. RouST guarantees communication safety for tion protocol between server and clients. endpoint web applications written using STScript APIs. We evaluate the expressiveness of STScript for modern B A S web programming using several production-ready case stud- Suggest Query ies deployed as web applications. alt Available arXiv:2101.04622v1 [cs.PL] 12 Jan 2021 CCS Concepts: • Software and its engineering → Source Quote code generation; • Theory of computation → Distributed computing models. alt OK Confirm Keywords: TypeScript, WebSocket, API generation, session No types, deadlock freedom, web programming Reject
the blue dashed arrows). It starts when a traveller (B) sug- uses binary (2-party) session types; and King et al.[20] re- gests a trip destination to their friend (A), who then queries quire each non-server role to only communicate to the server, the travel agency (S) if the trip is available. If so, the friends hence preventing interactions between non-server roles (cf. discuss among themselves whether to accept or reject the talking to a friend in the scenario). The programming lan- quoted price. If the trip was unavailable, the friends start guages used in these works are, respectively, Links [8] and again with a new destination. PureScript [28], both not usually considered mainstream An implementation of the travel agency protocol may in the context of modern web programming. The Jolie lan- contain programming errors, risking communication safety. guage [24] focuses more on the server side, with limited For example, the following implementation of the client-side support for an interactive front end of web applications. endpoint for traveller A sending a quote to traveller B. This paper presents a novel toolchain, Session TypeScript 1 (STScript), for implementing multiparty protocols safely in 2 web programming. STScript integrates with modern tools and 3 its flexibility over the traditional HTTP model. When de- There are subtle errors that violate the communication pro- velopers use our generated APIs to correctly implement the tocol, but these bugs are unfortunately left for the developer protocol endpoints, STScript guarantees the freedom from to manually identify and test against: communication errors, including deadlocks, communication Communication Mismatch Whilst the input field man- mismatches, channel usage violation or cancellation errors. dates a numerical value (Line1) for the quote, the value from Our toolchain is backed by a new session theory, a routed the input field is actually a string. If B expects a number multiparty session types theory (RouST), to endow servers and performs arithmetic operations on the received payload with the capacity to route messages between web clients. The from A, the type mismatch may be left hidden due to implicit new theory addresses a practical limitation that WebSocket type coercion and cause unintended errors. connections still require clients to connect to a prescribed Channel Usage Violation As B may take time to respond, server, constraining the ability for inter-client communica- A can experience a delay between sending the quote and tion. To overcome this, our API routes inter-client messages receiving a response. Notice that the button remains active through the server, improving the expressiveness over pre- after sending the quote — A could click on the button again, vious work and enabling developers to correctly implement and send additional quotes (thus reusing the communication multiparty protocols, as we show with blue dashed arrows channel), but B may be unable to deal with extra messages. in Fig.1. In our travel agency scenario, the agency plays Handling Session Cancellation An additional concern is the server role: it will establish WebSocket channels with how to handle browser disconnections, as both travellers can each participant, and be tasked with routing all the messages freely close their browsers at any stage of the protocol. Sup- between the friends. We formalise this routing mechanism pose S temporarily reserves a seat on A’s query. If A closes as RouST and prove deadlock-freedom of RouST and show a their browser, the developer would need to make sure that A behaviour-preserving encoding from the original MPST to notifies S prior to disconnecting, and S needs to implement RouST. The formalism and results in RouST directly guide recovery logic (e.g. releasing the reserved seat) accordingly. a deadlock-free protocol implementation in Node.js via the To prevent these errors and ensure deadlock-freedom, we router, preserving communication structures of the original propose to apply session types [14, 15] into practical interac- protocol written by a developer. tive web programming. The scenario described in Fig.1 can Finally, we evaluate our toolchain (STScript) by case stud- be precisely described with a global type using the typing ies. We evaluate the expressiveness by implementing a num- discipline of multiparty session types (MPST) [15]. Well-typed ber of web applications, such as interactive multiplayer games implementations conform to the given global protocol, are (Noughts and Crosses, Battleship) and web services (Travel guaranteed free from communication errors by construction. Agency) that require routed communication. Whereas session type programming is well-studied [1], its application on web programming, in particular, interactive Contributions and Structure of the Paper. §2 presents web applications, remains relatively unexplored. Integrat- an overview of our toolchain STScript, which generates APIs ing session types with web programming has been piloted for communication-safe web applications in TypeScript from by recent work [13, 20, 24], yet none are able to seamlessly multiparty protocol descriptions. §3 motivates how the gen- implement the previous application scenario: Fowler [13] erated code executes the multiparty protocol descriptions, 2 Communication-Safe Web Programming in TypeScript with Routed Multiparty Session Types CC ’21, March 2–3, 2021, Virtual, USA
A Global Type 퐺 Projection onto each Participant 푇A 푇B 푇S Local Type Local Type Local Type for A for B for S Figure 3. Top-down MPST Design Methodology
1 global protocol TravelAgency(roleA, roleB, roleS) 2 { Suggest(string) fromB toA;//friend suggests place 3 Query(string) fromA toS; 4 choice atS 5 { Available(number) fromS toA; 6 Quote(number) fromA toB;//check price with friend 7 choice atB 8 { OK(number) fromB toA; 9 Confirm(credentials) fromA toS;} 10 or { No() fromB toA; 11 Reject() fromA toS;}} 12 or { Full() fromS to A; Full() fromA toB; 13 do TravelAgency(A, B, S); } } Figure 2. Overview of the toolchain STScript Figure 4. Travel Agency Protocol in Scribble and present how STScript prevents common errors in the context of web applications. §4 presents RouST, multiparty respond to the query either with Available, so the customer session types (MPST) extended with routing, and define a continues booking, or with Full, so the customer retries by trace-preserving encoding of the original MPST into RouST. restarting the protocol via the do syntax (Line 13). §5 evaluates our toolchain STScript via a case study of In this scenario, we designate the roles A and B as client Noughts and Crosses and performance experiments. §6 roles, and role S as a server role. Participating endpoints gives related and future work. can obtain their local views of the communication proto- Appendix includes omitted code, definitions, performance col, known as local types, via projection from the specified benchmarks and detailed proofs. The artifact accompanying global type (Fig.3). The local type of an endpoint can be then this paper [23] is available via DOI or at https://github.com/ used in the code generation process, to generate APIs that STScript-2020/cc21-artifact, containing the source code of are correct by construction [17, 20, 35]. STScript, with implemented case studies and performance The code generation toolchain STScript (Fig.2) follows benchmarks. See AppendixA for details about the artifact. the MPST design philosophy. In STScript, we take the global protocol as inputs, and generate endpoint code for a given 2 Overview role as outputs, depending on the nature of the role. We In this section, we give an overview of our code generation use the Scribble toolchain for initial processing, and use an toolchain STScript (Fig.2), demonstrate how to implement endpoint finite state machine (EFSM) based code generation the travel agency scenario (Fig.1) as a TypeScript web appli- technique targeting the TypeScript Language. cation, and explain how STScript prevents those errors. Targeting Web Programming. The TypeScript [2] pro- Multiparty Session Type Design Workflow. Multiparty gramming language is used for web programming, with a session types (MPST) [15] use a top-down design method- static type system and a compiler to JavaScript. TypeScript ology (Fig.3). Developers begin with specifying the global programs follow a similar syntax to JavaScript, but may communication pattern of all participants in a global type contain type annotations that are checked statically by the or a global protocol. The protocol is described in the Scrib- TypeScript type-checker. After type-checking, the compiler ble protocol description language [16, 31, 34]. We show the converts TypeScript programs into JavaScript programs, so global protocol of the travel agency scenario (in §1) in Fig.4. they can be run in browsers and other hosts (e.g. Node.js). The Scribble language provides a user-friendly way to de- To implement a wide variety of communication patterns, scribe the global protocol in terms of a sequence of message we use the WebSocket protocol [12], enabling bi-directional exchanges between roles. A message is identified by its label communication between the client and the server after con- (e.g. Suggest, Query, etc), and carries payloads (e.g. number, nection. This contrasts with the traditional request-response string, etc). The choice syntax (e.g. Line4) describes pos- model of HTTP, where the client needs to send a request sible branches of the protocol – in this case, the Server may and the server may only send a response after receiving the 3 CC ’21, March 2–3, 2021, Virtual, USA Anson Miu, Francisco Ferreira, Nobuko Yoshida, and Fangyi Zhou
4 S?Full B!Full S?Available 1 2 3 5 B?Suggest S!Query B!Quote 7 S!Confirm B?Ok 9 6 S!Reject B?No 8 Figure 5. EFSM for TravelAgency role A request. WebSockets require an endpoint to listen for connec- tions and the other endpoint connecting. Moreover, clients, Figure 6. IDE Auto-Completion for Successor State using the web application in a browser, may only start a server, in this use case, namely providing quotes for holiday connection to a WebSocket, and servers may only listen for bookings and handling booking confirmations. new connections. The design of WebSocket limits the ability for two clients to communicate directly via a WebSocket (e.g. 1 import { Session, S } from"./TravelAgency/S"; Line2 in Fig.4). STScript uses the server to route messages 2 const agencyProvider = (sessionID: string) => { between client roles, enabling communication between all 3 const handleQuery = Session.Initial({ participants via a star network topology. 4 Query: async (Next, dest) => { An important aspect of web programming is the interac- 5 // Provide quotes for holiday bookings const res = await checkAvailability(sessionID, dest); tivity of the user interface (UI). Viewed in a browser, the web 6 7 if (res.status ==="available"){ application interacts with the user via UI events, e.g. mouse 8 return Next.Available([res.quote], Next => ...); clicks on buttons. The handling of UI events may be imple- 9 } else{ return Next.Full([], handleQuery); } }, }); mented to send messages to the client (e.g. when the “Submit” 10 return handleQuery; }; button on the form is clicked), which may lead to practical problems. For instance, would clicking “Submit” button twice All callbacks carry an extra parameter, Next, which acts as create two bookings for the customer? We use the popular a factory function for constructing the successor state. This React.js UI framework for generating client endpoints, and empowers IDEs to provide auto-completion for developers. generate APIs that prevent such errors from happening. For example, the factory function provided by the callback for handling a Query message (Line4) prompts the permitted Callback-Style API for Clients and Servers. Our code labels in the successor send state, as illustrated in Fig.6. generation toolchain STScript produces TypeScript APIs in a callback style [35] to statically guarantee channel linearity. Implementing the Client Roles. To implement client The input global protocol is analysed by the toolchain for roles, merely implementing the callbacks for the program well-formedness, and an endpoint finite state machine (EFSM) logic is not sufficient — unlike servers, web applications have is produced for each endpoint. We show the EFSM for role A interactive user interfaces, additional to program logic. As in Fig.5. The states in the EFSM represent local types (sub- mentioned previously, our code generation toolchain tar- ject to reductions) and transitions represent communication gets React.js for client roles. For background, the smallest actions (Symbol ! stands for sending actions, ? for receiving). building blocks in React.js are components, which can carry In the callback API style, type signatures of callbacks are properties (immutable upon construction) and states (muta- generated for transitions in the EFSM. Developers imple- ble). Components are rendered into HTML elements, and ment the callbacks to complete the program logic part of they are re-rendered when the component state mutates. the application, whilst a generated runtime takes care of the To bind the program logic with an interactive user in- communication aspects. For callbacks, sending actions cor- terface, we provide component factories that allow the UI respond to callbacks prompting the payload type as a return component to be interposed with the current state of the type, so that the returned value can be sent by the runtime. EFSM. Developers can provide the UI event handler to the Dually, receiving actions correspond to callbacks taking the component factory, and obtain a component for rendering. payload type as an argument, so that the runtime invokes The generate code structure enforces that the state transition the callback with the received value. strictly follows the EFSM, so programmer errors (such as the double “submit” problem) are prevented by design. Implementing the Server Role. In the travel agency pro- tocol, as shown in Fig.4, we designate role S as the server 1 render() { role. The server role does not only interact with the two 2 const OK = this.OK('onClick', () => [this.state.split]); const NO = this.No('onClick', () => []); clients, but also routes messages for the two clients. The 3 4 return (... routing will be handled automatically by the runtime, sav- 5 ing the need for developers to specify manually. As a result, 6 ...); } the developer only handles the program logic regarding the 4 Communication-Safe Web Programming in TypeScript with Routed Multiparty Session Types CC ’21, March 2–3, 2021, Virtual, USA
Using the send state component in the FSM for the end- for each kind of EFSM state – send, receive, or terminal. The point B as an example, Line2 reads, “generate a React com- generated State class implements the interface correspond- ponent that sends the OK message with this.state.split ing to the type of communication action it performs. as payload on a click event”. It is used on Line6 as a wrapper 1 next(state: State.Type) { for a stylised
endpoint). The session runtime detects cancellation by lis- as protocols and describe the communication behaviour be- tening to the close event on the WebSocket connection, and tween all participating roles (participants), while local types invokes the cancellation handler with appropriate arguments describe the behaviour of a single participating role. We on a premature close event. We parameterise the cancellation shade additions to the original (or canonical) multiparty ses- handlers with additional information (e.g. which role discon- sion type (MPST) [9, 11, 15, 30] in this colour. nected from the session, the reason for the disconnection) to Definition 4.1 (Global and Local Types). The syntax of let developers be more specific in their error handling logic. global and local types are defined below: = end | | = end | | | → { } Cancellation Handlers for Servers. Server endpoints 퐺 :: t 휇t.퐺 푇 :: t 휇t.푇 p ↩ q : 푙푖 :푇푖 푖 ∈퐼 | p → q : {푙 :퐺 } | p ⊕ {푙 :푇 } | p ⊕⟨q⟩ {푙 :푇 } define cancellation handlers through a function, parame- 푖 푖 푖 ∈퐼 푖 푖 푖 ∈퐼 푖 푖 푖 ∈퐼 | p −s q : {푙푖 :퐺푖 }푖 ∈퐼 | p & {푙푖 :푇푖 }푖 ∈퐼 | p &⟨q⟩ {푙푖 :푇푖 }푖 ∈퐼 terised by the session ID, the role which initiated the cancel- 푙 퐺 lation, and (optionally) the reason for the cancellation — if Global Types. p → q : { 푖 : 푖 }푖 ∈퐼 describes a direct com- 푙 the server-side logic throws an exception, the handler can munication of a message 푖 from a role p to q. We require 푙 access the thrown error through the reason parameter. that p ≠ q, that labels 푖 are pairwise distinct, and that the 퐼 const handleCancel = async (sessionID, role, reason) => { index set is not empty. The message in the communica- 1 푙 2 if (role === Role.Self) { tion can carry a label among a set of permitted labels 푖 푙 3 console.error(`${sessionID}: internal server error`); } and some payload. After a message with label 푖 is received 4 else{ await tryRelease(sessionID); }}; by q, the communication continues with 퐺푖 , according to 5 // Instantiate session runtime the chosen label. For simplicity, we do not include payload 6 new S(wss, handleCancel, agencyProvider); types (integers, strings, booleans, etc) in the syntax. We write Using the Travel Agency scenario introduced in §1, if the p → q : 푙 : 퐺 for single branches. For recursion, we adopt customer prematurely closes their browser before respond- an equi-recursive view [27, §21], and use 휇t.퐺 and t for a ing to a Quote, the server can detect this (Line4) and release recursive protocol and a type variable. We require that re- the reservation to preserve data integrity. cursive types are contractive (guarded), i.e. the recursive type 휇t.퐺 progresses after the substitution 퐺 [휇t.퐺/t], prohibiting Cancellation Handlers for Clients. Browser-side end- types such as 휇t.t. We use end to mark the termination of points also define cancellation handlers through a function the protocol, and often omit the final end. parameterised in the same way as those in Node.js, but must To support routed communication, we allow messages return a React component to be rendered by the session to be sent through a router role.A routed communication 푙 퐺 runtime. In the context of the Travel Agency scenario, the p −s q : { 푖 : 푖 }푖 ∈퐼 describes a router role s coordinating customer can render a different UI depending on whether the the communication of a message from p to q: q offers p a server disconnected or their friend closed their web browser choice in the index set 퐼, but p sends the selected choice 푙푖 to prematurely. Browser endpoints can also respond to cancel- the router s instead. The router forwards the selection from lations emitted by other client-side roles: when a browser p to q. After q receives p’s selection, the communication endpoint disconnects, the server detects this and propagates continues with 퐺푖 . s ranges over the set of roles p, q, ··· , the cancellation to the other client-side roles. but we use s by convention as the router is usually some server. The syntax for routed communication shares the 4 RouST: Routed Session Types same properties as direct communication, but we additionally 퐺 This section defines the syntax and semantics of RouST and require that p ≠ q ≠ s. We use pt ( ) to denote the set of 퐺 proves some important properties. We show the sound and participants in the global type . complete trace correspondence between a global type and Example 4.2 (Travel Agency). The travel agency protocol, a collection of endpoint types projected from the global as shown in Fig.4, is described by the global type 퐺travel in type (Theorem 4.6). Using this result, we prove deadlock 퐺푅 the original MPST, and travel in RouST. freedom (Theorem 4.7). We then show that, in spite of the 퐺travel = 휇t.B → A : 푆푢푔푔푒푠푡. A → S : 푄푢푒푟푦. added routed communications, RouST does not over-serialise 퐴푣푎푖푙푎푏푙푒 : communications by proving communication preservations be- A → B : 푄푢표푡푒. B → A : tween the original MPST and RouST (Theorem 4.11). These S → A : 푂퐾 : A → S : 퐶표푛푓 푖푟푚 three theorems ensure that STScript endpoint programs are 푁표 : A → S : 푅푒 푗푒푐푡 communication-safe, always make progress, and correctly 퐹푢푙푙 : A → B : 퐹푢푙푙. t 푅 = − → conforms to the user-specified protocol. 퐺travel 휇t.B S A : 푆푢푔푔푒푠푡. A S : 푄푢푒푟푦. 퐴푣푎푖푙푎푏푙푒 : A −S B : 푄푢표푡푒. B −S A : 4.1 Syntax of Routed Multiparty Session Types S → A : 푂퐾 : A → S : 퐶표푛푓 푖푟푚 We define the syntax of global types 퐺 and local types (or end- 푁표 : A → S : 푅푒 푗푒푐푡 푇 point types) in Definition 4.1. Global types are also known 퐹푢푙푙 : A −S B : 퐹푢푙푙. t 6 Communication-Safe Web Programming in TypeScript with Routed Multiparty Session Types CC ’21, March 2–3, 2021, Virtual, USA
Local Types. We first describe the local types in the orig- Well-formedness. In the original theory, a global type 퐺 푙 푇 퐺 inal MPST theory. q & { 푖 : 푖 }푖 ∈퐼 stands for branching and is well-formed (or realisable), denoted wellFormed ( ), if the 푙 푇 q ⊕ { 푖 : 푖 }푖 ∈퐼 stands for selection. From the perspective of projection is defined for all its participants. p def , branching (resp. selection) offers (resp. selects) a choice wellFormed (퐺) = ∀p ∈ pt (퐺).퐺 ↾p exists among an index set 퐼 to (resp. from) q, and communication We assume that the global type 퐺 is contractive (guarded). continues with the corresponding 푇 . Local types 휇t.푇 , t and 푖 In RouST, we say that a global type is well-formed with end have the same meaning as their global type counterparts. respect to the role s acting as the router. We define the charac- We add new syntax to express routed communication teristics that s must display in 퐺 to prove that it is a router, from the perspective of each role involved. The local type and formalise this as an inductive relation, 퐺 ⊛ s (Defini- p &⟨s⟩ {푙 :푇 } is a routed branching: the current role is 푖 푖 푖 ∈퐼 tion 4.5), which reads s is a centroid in 퐺. The intuition is offering a choice from an index set 퐼 to p (the intended that s is at the centre of all communication interactions. sender), but expects to receive p’s choice via the router role 퐺 s; if the message received is labelled 푙 , q will continue with Definition 4.5 (Centroid). The relation ⊛ s (s is the cen- 푖 퐺 end local type 푇 . The local type q ⊕⟨s⟩ {푙 :푇 } is a routed se- troid of ) is defined by the two axioms ⊛ s and t ⊛ s 푖 푖 푖 푖 ∈퐼 and by the following rules: lection: the current role makes a selection from an index set 퐼 to q (the intended recipient), but sends the selection 퐺 ⊛ s s ∈ {p, q} ∀푖 ∈ 퐼.퐺 푖 ⊛ s r = s ∀푖 ∈ 퐼.퐺 푖 ⊛ s 푙 to the router role s; if the message sent is labelled 푖 , p will 휇t.퐺 ⊛ s p → q : {푙푖 : 퐺푖 }푖 ∈퐼 ⊛ s p −r q : {푙푖 :퐺푖 }푖 ∈퐼 ⊛ s continue with local type 푇 . The local type p ↩→ q : {푙 :푇 } 푖 푖 푖 푖 ∈퐼 For direct communication, s must be a participant and a is a routing communication. The router role orchestrates centroid of all continuations. For routed communication, s the communication from p to q, and continues with local must be the router and be a centroid of all continuations. Now type 푇 depending on the label of the forwarded message. 푖 we define of well-formedness of a global type 퐺 in RouST We keep track of the router role to distinguish between rout- with respect to the router s (denoted wellFormed푅 (퐺, s)): ing communications from normal selection and branching 푅 def interactions. wellFormed (퐺, s) = (∀p ∈ pt (퐺).퐺 ↾p exists) ∧ 퐺 ⊛ s
Endpoint Projection. The local type 푇 of a participant p 4.2 Semantics of RouST in a global type 퐺 is obtained by the endpoint projection of 퐺 This subsection defines the labelled transition system (LTS) onto p, denoted by 퐺 as 퐺 ↾p. over global types for RouST, building upon [11]. First, we define the labels (actions) in the LTS which dis- Definition 4.3 (Projection). The projection of 퐺 onto r, tinguish the direct sending (and reception) of a message from written 퐺 ↾r is defined as: the sending (and reception) of a message via an intermediate ( − { } ) p s q : 푙푖 :퐺푖 푖 ∈퐼 ↾r (휇t.퐺) ↾r routing endpoint. Labels range over 푙, 푙 ′, ··· are defined by: ( ′ q ⊕⟨s⟩ {푙푖 :퐺푖 ↾r}푖 ∈퐼 if r = p 휇t.(퐺 ↾r) if 퐺 ↾r ≠ t = 푙 ::= pq!푗 | pq?푗 | via⟨s⟩(pq!푗) | via⟨s⟩(pq?푗) p &⟨s⟩ {푙 :퐺 ↾r} if r = q = 푖 푖 푖 ∈퐼 end otherwise The label via⟨s⟩(pq!푗) represents the sending (performed p ↩→ q : {푙푖 :퐺푖 ↾r}푖 ∈퐼 if r = s end↾r = end by p) of a message labelled 푗 to q through the intermediate ⊓ 퐺 ↾r otherwise t↾r = t 푖 ∈퐼 푖 router s. The label via⟨s⟩(pq?푗) represents the reception ( → {푙 퐺 )} The projection p q : 푖 : 푖 푖 ∈퐼 ↾ r is defined similar to (initiated by q) of a message labelled 푗 send from p through ( − {푙 퐺 } ) p s q : 푖 : 푖 푖 ∈퐼 ↾ r dropping s (in the resulting local the intermediate router s. The subject of a label 푙, denoted by type) and the third case. subj(푙), is defined as: subj(via⟨s⟩(pq!푗)) = subj(pq!푗) = p; A merge operator (⊓) is used when projecting a communi- and subj(via⟨s⟩(pq?푗)) = subj(pq?푗) = q. cation onto a non-participant. It checks that the projections LTS Semantics over Global Types. The LTS semantics of all continuations must be “compatible” (see Definition B.2). model asynchronous communication to reflect our imple- mentation. We introduce intermediate states (i.e. messages Example 4.4 (Merging Local Types). Two branching types in transit) within the grammar of global types: the con- .푗 푙 퐺 푙 from the same role with disjoint labels can merged into a type struct p ⇝ q : { 푖 : 푖 }푖 ∈퐼 represents that the message 푗 carrying both labels, e.g. A & 퐻푒푙푙표.end ⊓ A & 퐵푦푒.end = has been sent by p but not yet received by q; and the con- .푗 푙 퐺 푙 A & {퐻푒푙푙표 : end; 퐵푦푒 : end}. The same is not true for selec- struct p ⇝ q : { 푖 : 푖 }푖 ∈퐼 represents that 푗 has been sent s tions, A ⊕ 퐻푒푙푙표.end ⊓ A ⊕ 퐵푦푒.end is undefined. from p to the router s but not yet routed to q. We define the 푙 퐺푟푒푒푡 : A → C : 퐻푒푙푙표. end LTS semantics over global types, denoted by 퐺 −−→ 퐺 ′, in 퐺1 = A → B : 퐹푎푟푒푤푒푙푙 : A → C : 퐵푦푒. end Fig.7.[ Gr1] and [Gr2] model the emission and reception 퐺푟푒푒푡 : C → A : 퐻푒푙푙표. end 퐺 = A → B of a message; [Gr3] models recursions; [Gr4] and [Gr5] 2 : → 퐹푎푟푒푤푒푙푙 : C A : 퐵푦푒. end model causally unrelated transmissions — we only enforce The global type 퐺1 can be projected to role C, but not 퐺2. the syntactic order of messages for the participants involved 7 CC ’21, March 2–3, 2021, Virtual, USA Anson Miu, Francisco Ferreira, Nobuko Yoshida, and Fangyi Zhou
[Gr6] [Gr1] via⟨s⟩(pq!푗) pq 푗 ! p −s q : {푙푖 :퐺푖 }푖 ∈퐼 −−−−−−−−→ p ⇝ q.푗 : {푙푖 :퐺푖 }푖 ∈퐼 p → q : {푙푖 :퐺푖 }푖 ∈퐼 −−−−−−−−→ p ⇝ q.푗 : {푙푖 :퐺푖 }푖 ∈퐼 s 푙 ′ [Gr2] 퐺 [휇t.퐺/t] −−→ 퐺 [Gr7] pq?푗 [Gr3] via⟨s⟩(pq?푗) p ⇝ q.푗 : {푙 :퐺 } −−−−−−−−→ 퐺 푙 ′ p ⇝ q.푗 : {푙푖 :퐺푖 } ∈ −−−−−−−−→ 퐺 푗 푖 푖 푖 ∈퐼 푗 휇t.퐺 −−→ 퐺 s 푖 퐼 푙 ∀푖 ∈ 퐼.퐺 −−→ 퐺 ′ subj(푙) ∉ {p, q} 푙 ′ 푖 푖 ∀푖 ∈ 퐼.퐺 푖 −−→ 퐺 subj(푙) ∉ {p, q} [Gr4] 푖 [Gr8] 푙 ′ 푙 p → q : {푙푖 :퐺푖 }푖 ∈퐼 −−−−−−−−→ p → q : 푙푖 :퐺 ′ 푖 푖 ∈퐼 p −s q : {푙푖 :퐺푖 }푖 ∈퐼 −−−−−−−−→ p −s q : 푙푖 :퐺푖 ∈ 푖 퐼 푙 퐺 −−→ 퐺 ′ subj(푙) ≠ q ∀푖 ∈ 퐼 \{푗}.퐺 ′ = 퐺 푙 ′ ′ 푗 푗 푖 푖 퐺 푗 −−→ 퐺 subj(푙) ≠ q ∀푖 ∈ 퐼 \{푗}.퐺 = 퐺푖 [Gr5] 푗 푖 푙 [Gr9] p ⇝ q.푗 : {푙 :퐺 } −−−−−−−−→ p ⇝ q.푗 : 푙 :퐺 ′ 푙 ′ 푖 푖 푖 ∈퐼 푖 푖 푖 ∈퐼 p ⇝ q.푗 : {푙푖 :퐺푖 } ∈ −−−−−−−−→ p ⇝ q.푗 : 푙푖 :퐺 s 푖 퐼 s 푖 푖 ∈퐼 Figure 7. LTS over Global Types in RouST in the action 푙.[Gr6] and [Gr7] are analogous to [Gr1] and wellFormed푅 (퐺, s). Then we have: 푙 [Gr2] for describing routed communication, but uses the ∀퐺 ′. 퐺 →∗ 퐺 ′ =⇒ (퐺 ′ = end) ∨ ∃퐺 ′′,푙. (퐺 ′ −−→ 퐺 ′′) “routed in-transit” construct instead. [Gr8] and [Gr9] are analogous to [Gr4] and [Gr5]. An important observation from [Gr8] and [Gr9] is that, for the router, the syntactic 4.3 From Canonical MPST to RouST order of routed communication can be freely interleaved We present an encoding from the canonical MPST theory between the syntactic order of direct communication. This (no routers) to RouST. This encoding is parameterised by is crucial to ensure that the router does not over-serialise the router role (conventionally denoted as s); the intuition communication. See Example 4.13 for an LTS example. is that we encode all communication interactions to involve s. If the encoding preserves the semantics of the canonical Relating Semantics of Global and Local Types. We prove global type, then this encoding can guide a correct protocol the soundness and completeness of our LTS semantics with implementation in Node.js via s, preserving communication respect to projection. We take three steps following [11]: structures of the original protocol without deadlock. 1. We extend the LTS semantics with configuration (푇ì, 푤ì), Router-Parameterised Encoding. a collection of local types 푇ì with FIFO queues between We define the router- each pair of participants 푤ì. parameterised encoding on global types, local types and 2. We extend the definition of projection, to obtain a config- LTS labels in the MPST theory. We start with global types, uration of a global type (a projected configuration), which as presented in Definition 4.8. The main rule is the direct s expresses intermediate communication over FIFO queues. communication: if the communication did not go through , s 3. We prove the trace equivalence between the global type then the encoded communication involves as the router. and its projected configuration (i.e. the initial configura- Definition 4.8 (Encoding on Global Types). The encoding 퐺 푇ì, 휖 푇ì 퐺 tion of , ( ì), where = { ↾ p}p∈P are a set of local of global type 퐺 with respect to the router role s, denoted by 퐺 휖 types projected from and is an empty queue). 퐺, s , is defined as: J K The proof is non-trivial: due to space limitations, we omit end, s = end t, s = t 휇t.퐺, s = 휇t. 퐺, s J K J( K J K J K the semantics of local types, configurations and global con- → ∈ { } p q : 푙푖 : 퐺푖, s 푖 ∈퐼 if s p,q figurations, and only state the main result (see AppendicesB p → q : {푙푖 :퐺푖 }푖 ∈퐼 , s = J K J K p −s q : 푙푖 : 퐺푖, s ∈ otherwise andC). J K 푖 퐼
Theorem 4.6 (Sound and Complete Trace Equivalence). Let Local types express communication from the perspective 퐺 be a well-formed canonical global type. Then 퐺 is trace of a particular role, hence the encoding takes two roles. equivalent to its initial configuration. Definition 4.9 (Encoding on Local Types). The encoding Theorem 4.7 proves traces specified by a well-formed of local type 푇 (from the perspective of role q) with respect global protocol are deadlock-free, i.e. the global type either to the router role s, denoted by 푇, q, s , is defined as: J K completes all communications, or otherwise makes progress. end, q, s = end t, q, s = t 휇t.푇, q, s = 휇t. 푇, q, s J K J ( K J K J K Note that this theorem implies the deadlock-freedom of con- ⊕ ∈ { } p 푙푖 : 푇푖, q, s 푖 ∈퐼 if s p,q figurations by Theorem 4.6. p ⊕ {푙푖 :푇푖 } ∈ , q, s = 푖 퐼 ⊕⟨ ⟩ J K J K p s 푙푖 : 푇푖, q, s 푖 ∈퐼 otherwise ( J K Theorem 4.7 (Deadlock Freedom). Let 퐺 be a global type. p & 푙푖 : 푇푖, q, s if s ∈ {p,q} p & {푙 :푇 } , q, s = 푖 ∈퐼 퐺 푖 푖 푖 ∈퐼 ⟨ ⟩ J K Suppose is well-formed with respect to some router s, i.e. J K p & s 푙푖 : 푇푖, q, s 푖 ∈퐼 otherwise 8 J K Communication-Safe Web Programming in TypeScript with Routed Multiparty Session Types CC ’21, March 2–3, 2021, Virtual, USA
Lemma 4.10 (Correspondence between Encodings). The 5 Evaluation 퐺, projection of an encoded global type s ↾r is equal to the In this section, we demonstrate the expressiveness and ap- 퐺J , ,K encoded local type after projection ↾r r s , with respect to plicability of STScript for modern web programming, and , ,퐺. 퐺J, K퐺 , , router s, i.e. ∀r s r ≠ s =⇒ s ↾r = ↾r r s . report on performance. We walk through how to implement J K J K Noughts and Crosses game with our toolchain, showing how The constraint r ≠ s is necessary because we would other- the generated APIs prevent common errors. We choose this wise lose information on the right-hand side of the equality: game since we can demonstrate the main features of STScript the projection of s in the original communication does not within the limited space. We also remark on performance contain the routed interactions, so applying the local type implications of our toolchain. In AppendixD, we include encoding cannot recover this information. larger cases studies: Battleship, a game with more complex Theorem 4.11 (Encoding Preserves Well-Formedness). Let program logic; and Travel Agency (Fig.1), as shown in §1. 퐺 be a global type, and s be a role. Then we have: Noughts and Crosses. We present the classic two-player 푅 wellFormed (퐺) ⇐⇒ wellFormed 퐺, s , s turn-based game of Noughts and Crosses here. We formalise J K the game interactions using a Scribble protocol: both players, Preserving Communication. We present a crucial re- identified by noughts (O’s) or crosses (X’s), take turns to place sult that directly addresses the pitfalls of naive definitions a mark on an unoccupied cell of a grid, until a player wins of routed communication — our encoding does not over- (when their markers form a straight line) or a stalemate is serialise the original communication. We prove that our reached (when all cells are occupied and no one wins). encoding preserves the LTS semantics over global types — 1 // `Pt` stands for the position on the board or more precisely, we can use the encodings over global 2 global protocol Game(role Svr, role P1, role P2) { types and LTS actions to encode all possible transitions 3 Pos(Pt) from P1 to Svr; in the LTS for global types in the canonical MPST theory. 4 choice at Svr We define the encoding of label 푙 in the original MPST as: 5 { Lose(Pt) from Svr to P2; Win(Pt) from Svr to P1; } pq!푗, s = via⟨s⟩(pq!푗) and pq?푗, s = via⟨s⟩(pq?푗) if 6 or { Draw(Pt) from Svr to P2; Draw(Pt) from Svr to P1; } Js ∉ {p,qK} and otherwise 푙, s =J 푙. K 7 or { Update(Pt) from Svr to P2; Update(Pt) from Svr to P1; J K 8 do Game(Svr, P2, P1); }}// Players swap turns Theorem 4.12 (Encoding Preserves Semantics). Let 퐺,퐺 ′ 푙 Game Server. We set up the game server as an Express.js be well-formed global types such that 퐺 −−→ 퐺 ′ for some label application on top of the Node.js runtime. We define our 푙. Then we have: own game logic in a Board class to keep track of the game 푙 푙, s state and expose methods to query the result. When the ∀푙, s. 퐺 −−→ 퐺 ′ ⇐⇒ 퐺, s −−−−−−−−→J K 퐺 ′, s J K J K server receives a move, it notifies the game logic to update the game state asynchronously and return the game result We conclude with an example which demonstrates global caused by that move. The expressiveness of STScript enable semantics in RouST and a use of the encoding. the developer to define the handlers as async functions to Example 4.13 (Encoding Preserves Semantics). Consider use the game logic API correctly – this is prevalent in modern the global type web programming, but not directly addressed in [13, 20]. The generated session runtime for Node.js is given as: 퐺 푀 . 푀 . . = p → q : 1 s → q : 2 end 1 const gameManager = (gameID: string) => { We apply our encoding with respect to the router role s: 2 const handleP1Move = Session.Initial({ 3 Pos: async (Next, move: Point) => { 퐺, 푀 . 푀 . . s = p −s q : 1 s → q : 2 end 4 // Update current game with new move, return result J K We note that 푙 = sq!푀2 can reduce 퐺 through [Gr1] (via one 5 switch(await DB.attack(gameID, 'P1', move)) { case MoveResult.Win: application of [Gr4]). After encoding, we have that 푙, s = 푙. 6 7 // Send losing result to P2, winning result to P1 The encoded global type 퐺, s can be reduced by 푙JthroughK J K 8 return Next.Lose([move], Next => ( [Gr1] (via one application of [Gr8]), as demonstrated by 9 Next.Win([move], Session.Terminal)))); 푙 푀 Theorem 4.12. The label = sq! 2 is a prefix of a valid 10 case MoveResult.Draw: ... execution trace for 퐺, given below. 11 case MoveResult.Continue: 12 // Notify both players and proceed to P2's turn 퐺 sq!푀2 pq!푀1 pq?푀1 sq?푀2 −−−−−−−−→ −−−−−−−−→ −−−−−−−−→ −−−−−−−−→ end 13 return Next.Update([move], Next => ( Interested readers can verify that the encoded trace (given 14 Next.Update([move], handleP2Move)) }}}); const handleP2Move = ...// defined similarly below) is a valid execution trace for 퐺, s . 15 J K 16 return handleP1Move; } sq!푀2 via⟨s⟩(pq!푀1) via⟨s⟩(pq?푀1) sq?푀2 // Initialise game server 퐺, s −−−−−−−−→ −−−−−−−−−−−→ −−−−−−−−−−−→ −−−−−−−−→ end 17 J K 18 new Svr(wss, handleCancellation, gameManager); 9 CC ’21, March 2–3, 2021, Virtual, USA Anson Miu, Francisco Ferreira, Nobuko Yoshida, and Fangyi Zhou
The runtime is initialised by a function parameterised by the Table 1. Comparison of Message Processing Time for 100 session ID and returns the initial state. The developer can use and 1000 Ping-Pongs the session ID as an identifier to keep track of concurrent 푛 Msg. Proc. Time (ms) sessions and update the board of the corresponding game. Node.js React.js bare mpst bare mpst Game Players. On the browser side, the main implemen- tation detail for game players is to make moves. Intuitively, 102 0.194 0.201 0.499 0.961 the developer implements a grid and binds a mouse click 103 0.154 0.157 0.465 0.766 handler for each vacant cell to send its coordinates in a Pos(Point) message to the game server. Without STScript, both endpoints repeatedly exchange 푛 messages of increas- developers need to synchronise the UI with the progression ing integer values. This protocol is communication-intensive, of protocol manually — for instance, they need to guarantee which demonstrates the overhead of our generated runtime. that the game board is inactive after the player makes a move, and manual efforts are error-prone and unscalable. Setup. To measure the overhead as accurately as possible, The generated APIs from STScript make this intuitive, and we specify that the implementations must follow: guarantees communication safety in the meantime. By pro- • Clients implement the same user interface, rendering a viding React component factories for send states, the APIs
); }}; The developer implements the receive state S29 by extending from the corresponding abstract class, and implements the required abstract methods to define how to handle a Full message (Line6) or a Quote message (Line 11). FriendView.tsx import { B } from"../../TravelAgency/B";