Modular Verification of Message Passing Programs

Slides:



Advertisements
Similar presentations
Automated Theorem Proving Lecture 1. Program verification is undecidable! Given program P and specification S, does P satisfy S?
Advertisements

An Abstract Interpretation Framework for Refactoring P. Cousot, NYU, ENS, CNRS, INRIA R. Cousot, ENS, CNRS, INRIA F. Logozzo, M. Barnett, Microsoft Research.
Semantics Static semantics Dynamic semantics attribute grammars
Translation-Based Compositional Reasoning for Software Systems Fei Xie and James C. Browne Robert P. Kurshan Cadence Design Systems.
Constraint Semantics for Abstract Read Permissions 28 th July 2014, FTfJP, Uppsala John Tang Boyland (UW-Milwaukee/ETH Zurich) Peter Müller, Malte Schwerhoff,
Automated Software Verification with a Permission-Based Logic 20 th June 2014, Zürich Malte Schwerhoff, ETH Zürich.
Rigorous Software Development CSCI-GA Instructor: Thomas Wies Spring 2012 Lecture 11.
© M. Winter COSC 4P41 – Functional Programming Testing vs Proving Testing –uses a set of “typical” examples, –symbolic testing, –may find errors,
Formal Semantics of Programming Languages 虞慧群 Topic 5: Axiomatic Semantics.
Chair of Software Engineering The alias calculus Bertrand Meyer ITMO Software Engineering Seminar June 2011.
Silberschatz, Galvin and Gagne ©2013 Operating System Concepts – 9 th Edition Chapter 5: Process Synchronization.
Non-monotonic Properties for Proving Correctness in a Framework of Compositional Logic Koji Hasebe Mitsuhiro Okada (Dept. of Philosophy, Keio University)
CIS 540 Principles of Embedded Computation Spring Instructor: Rajeev Alur
ISBN Chapter 3 Describing Syntax and Semantics.
CS 355 – Programming Languages
Formal Methods of Systems Specification Logical Specification of Hard- and Software Prof. Dr. Holger Schlingloff Institut für Informatik der.
Comp 205: Comparative Programming Languages Semantics of Imperative Programming Languages denotational semantics operational semantics logical semantics.
Fractional Permissions without the Fractions Alex Summers ETH Zurich Joint work with: Stefan Heule, Rustan Leino, Peter Müller ETH Zurich MSR Redmond ETH.
Lecture 2 Towards a Verifying Compiler: Logic of Object oriented Programs Wolfram Schulte Microsoft Research Formal Methods 2006 Objects, references, heaps,
Proof System HY-566. Proof layer Next layer of SW is logic and proof layers. – allow the user to state any logical principles, – computer can to infer.
Chapter 8 . Sequence Control
Copyright © 2006 The McGraw-Hill Companies, Inc. Programming Languages 2nd edition Tucker and Noonan Chapter 18 Program Correctness To treat programming.
A logic for reasoning about digital rights Riccardo Pucella, Vicky Weissman Cornell University.
Describing Syntax and Semantics
Proof by Deduction. Deductions and Formal Proofs A deduction is a sequence of logic statements, each of which is known or assumed to be true A formal.
Configuration Management
Proving termination conditions Name Country, City, University Omer Subasi Turkey, Istanbul, Koc University Anton Dergunov
Procedure specifications CSE 331. Outline Satisfying a specification; substitutability Stronger and weaker specifications - Comparing by hand - Comparing.
RELATIONAL FAULT TOLERANT INTERFACE TO HETEROGENEOUS DISTRIBUTED DATABASES Prof. Osama Abulnaja Afraa Khalifah
SWE 619 © Paul Ammann Procedural Abstraction and Design by Contract Paul Ammann Information & Software Engineering SWE 619 Software Construction cs.gmu.edu/~pammann/
Chapter 25 Formal Methods Formal methods Specify program using math Develop program using math Prove program matches specification using.
Supported by ELTE IKKK, Ericsson Hungary, in cooperation with University of Kent Erlang refactoring with relational database Anikó Víg and Tamás Nagy Supervisors:
1 Concurrency Architecture Types Tasks Synchronization –Semaphores –Monitors –Message Passing Concurrency in Ada Java Threads.
A Universe-Type-Based Verification Technique for Mutable Static Fields and Methods Alexander J Summers Sophia Drossopoulou Imperial College London Peter.
COP4020 Programming Languages Introduction to Axiomatic Semantics Prof. Robert van Engelen.
CSE 486/586, Spring 2013 CSE 486/586 Distributed Systems Global States Steve Ko Computer Sciences and Engineering University at Buffalo.
13 Aug 2013 Program Verification. Proofs about Programs Why make you study logic? Why make you do proofs? Because we want to prove properties of programs.
ANU COMP2110 Software Design in 2003 Lecture 10Slide 1 COMP2110 Software Design in 2004 Lecture 12 Documenting Detailed Design How to write down detailed.
Lightweight Support for Magic Wands in an Automatic Verifier Malte Schwerhoff and Alexander J. Summers 10 th July 2015, ECOOP, Prague.
Conceptualization Relational Model Incomplete Relations Indirect Concept Reflection Entity-Relationship Model Incomplete Relations Two Ways of Concept.
Properties as Processes : FORTE slide Properties as Processes: their Specification and Verification Joel Kelso and George Milne School of Computer.
An Introduction to Automated Program Verification with Permission Logics 15 th May 2015, Systems Group, ETH Zurich Uri Juhasz, Ioannis Kassios, Peter Müller,
Soundness of Types Ensuring that a type system is not broken.
MOPS: an Infrastructure for Examining Security Properties of Software Authors Hao Chen and David Wagner Appears in ACM Conference on Computer and Communications.
Operational Semantics Mooly Sagiv Reference: Semantics with Applications Chapter 2 H. Nielson and F. Nielson
CIS 540 Principles of Embedded Computation Spring Instructor: Rajeev Alur
Logical Agents. Outline Knowledge-based agents Logic in general - models and entailment Propositional (Boolean) logic Equivalence, validity, satisfiability.
Spring 2017 Program Analysis and Verification
Arab Open University 2nd Semester, M301 Unit 5
The Relationship Between Separation Logic and Implicit Dynamic Frames
Reasoning About Code.
Reasoning about code CSE 331 University of Washington.
Joint work with Yong Li, Xinyu Feng, Zhong Shao and Yu Zhang
State your reasons or how to keep proofs while optimizing code
B (The language of B-Method )
Methods The real power of an object-oriented programming language takes place when you start to manipulate objects. A method defines an action that allows.
Important Concepts from Clojure
Important Concepts from Clojure
Mathematical Structures for Computer Science Chapter 1
Lecture 5 Floyd-Hoare Style Verification
Programming Languages and Compilers (CS 421)
Programming Languages 2nd edition Tucker and Noonan
Denotational Semantics (Denotational Semantics)
Logic for Computer Security Protocols
Language-Independent Verification Framework
Sub-system interfaces
Programming Languages and Compilers (CS 421)
Programming Languages 2nd edition Tucker and Noonan
A Considerate Specification of the Composite Pattern
Presentation transcript:

Modular Verification of Message Passing Programs Actor Services Modular Verification of Message Passing Programs ↝ 20th May 2016 Dagstuhl Seminar 16201 Alexander J. Summers Peter Müller ETH Zurich, Switzerland

Passing messages for the next ESOP ! ESOP 2017 Prof. Alice

Passing messages for the next ESOP alice.tell(conf) ↝ conf.submit(_) ESOP 2017 Prof. Alice idea idea + plan Dr. Bob (PhD student) this.exps(_) ↝ this.mentor.results(_) running experiments…

Passing messages for the next ESOP alice.tell(conf) ↝ conf.submit(_) ESOP 2017 Prof. Alice idea idea + plan Dr. Bob (PhD student) bob.propose(idea) ↝ this.exps(_) ↝ this.mentor.results(_) running experiments…

Passing messages for the next ESOP alice.tell(conf) ↝ conf.submit(_) ESOP 2017 Prof. Alice idea idea + plan Dr. Bob (PhD student) bob.propose(idea) ↝ alice.response(idea) this.exps(_) ↝ this.mentor.results(_) running experiments…

Passing messages for the next ESOP alice.tell(conf) ↝ conf.submit(_) ESOP 2017 Prof. Alice idea idea + plan Dr. Bob (PhD student) bob.propose(idea) ↝ alice.response(idea) where idea.name == old(idea.name) && idea.plan != null this.exps(_) ↝ this.mentor.results(_) running experiments…

Actor Services Novel assertions specifying response properties trigger message responsemessage bob.propose(idea) ↝ alice.response(idea) where idea.name == old(idea.name) … Novel assertions specifying response properties May depend on actor instance, program state Abstract over how property is guaranteed number of intervening messages / actors involved but, some finite sequence of messages Where-clauses express functional properties concerning message arguments and program heap two-state assertions relate heap@response to heap@trigger

Actor Services: Intuitive Semantics trigger message responsemessage bob.propose(idea) ↝ alice.response(idea) where idea.name == old(idea.name) … Related to LTL property: ⃞(trigger ⇒ ⃟response) We incorporate stateful properties, incl. shared heap Our semantics avoids explicit traces (non-modular) trigger response where condition

Mnesia distributed database protocol (Ericsson)

Mnesia distributed database protocol (Ericsson)

Mnesia distributed database protocol (Ericsson)

Mnesia distributed database protocol (Ericsson)

Mnesia distributed database protocol (Ericsson) query_setup

Mnesia distributed database protocol (Ericsson) query_setup

Mnesia distributed database protocol (Ericsson) query_setup next

Mnesia distributed database protocol (Ericsson) query_setup next next

Mnesia distributed database protocol (Ericsson) query_setup next next next

Mnesia distributed database protocol (Ericsson) next next query_setup next next next

Mnesia distributed database protocol (Ericsson) next next query_setup ready next next next

Mnesia distributed database protocol (Ericsson) next next query_setup ready req next next next

Mnesia distributed database protocol (Ericsson) sols next query_setup ready req next next next

Mnesia distributed database protocol (Ericsson) sols sols query_setup ready req next next next

Mnesia distributed database protocol (Ericsson) sols sols query_setup ready req sols sols sols

Mnesia distributed database protocol (Ericsson) sols sols query_setup enough? ready req sols sols sols

Mnesia distributed database protocol (Ericsson) sols query_setup ready req

Mnesia distributed database protocol (Ericsson) sols sols query_setup ready req

Mnesia distributed database protocol (Ericsson) sols sols query_setup ready req sols sols sols

Mnesia distributed database protocol (Ericsson) sols sols query_setup enough? ready req sols sols sols

Mnesia distributed database protocol (Ericsson) sols sols query_setup ready req sols response sols sols Want to prove: a request will eventually get a response (Ericsson verification case study [Arts & Dam ‘99])

Programming Language handler query_setup(Query query, User u) { val subqueries := // break down query - non-empty var n := this; for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } Actors have implicit mailboxes, and receive loops (active objects)

Programming Language handler query_setup(Query query, User u) { val subqueries := // break down query - non-empty var n := this; for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } Actors have implicit mailboxes, and receive loops (active objects) Actor classes declare handlers to execute on message receive

Programming Language handler query_setup(Query query, User u) { val subqueries := // break down query - non-empty var n := this; for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } Actors have implicit mailboxes, and receive loops (active objects) Actor classes declare handlers to execute on message receive Handler code may send messages, no blocking operations

Local Actor Services handler query_setup(Query query, User u) { val subqueries := // break down query - non-empty var n := this; for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } M.query_setup(Q,U) ↝ U.ready(M) Local actor service: provable using code of single message handler

Deriving actor services Local services: response sent directly by message handler the base-cases for deriving actor services Derivation rules prescribe when an actor service holds e.g. actor services can be composed : Where-conditions must also be combined (three states) M.query_setup(Q,U) ↝ U.ready(M) (x.query_setup(Q,user) ↝ user.ready(x)) && (user.ready(x) ↝ m.req(…)) ⊨ x.query_setup(Q,user) ↝ m.req(…) see the paper!

Composition and heap expressions e.g. query workers (another local actor service): we interpret W.next in state when response is sent Suppose we have instances x, y with x.next == y Similar composition? … Only sound if x.next will not be modified in future W.sols(S,P) ↝ W.next.sols(S,P) (x.sols(S,P) ↝ x.next.sols(S,P)) && (y.sols(S,P) ↝ y.next.sols(S,P)) ⊨ x.sols(S,P) ↝ y.next.sols(S,P)

Permissions, Immutability, Future States Two kinds of permissions to heap locations Exclusive permission, denoted acc(e.f) ownership, sendable via messages (preconditions) Immutable permission, denoted immut(e.f) only allows reading, freely duplicable Can freeze locations: transmute acc into immut Define future states relation: Σ1 ≼ Σ2 iff any immut location in Σ1 is immut in Σ2 and the value of that location is the same in Σ1,Σ2 Assertions depending only on immutable locations can be projected to future states (x.next == y on prev. slide)

Mnesia distributed database protocol (Ericsson) query_setup

Mnesia distributed database protocol (Ericsson) query_setup next

Mnesia distributed database protocol (Ericsson) query_setup next next

Mnesia distributed database protocol (Ericsson) query_setup next next next

Deriving Actor Services handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); }

Deriving Actor Services handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } (i=0 ⇒ n = this) && (i>0 ⇒

Deriving Actor Services handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } (i=0 ⇒ n = this) && (i>0 ⇒ n.sols(S,P) ↝ this.sols(_,P))

Deriving Actor Services handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } (i=0 ⇒ n = this) && (i>0 ⇒ n.sols(S,P) ↝ this.sols(_,P))

Deriving Actor Services handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } (i=0 ⇒ n’= this) && (i>0 ⇒ n’.sols(S,P) ↝ this.sols(_,P))

Deriving Actor Services handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } (i=0 ⇒ n’= this) && (i>0 ⇒ n’.sols(S,P) ↝ this.sols(_,P)) && (n.sols(S,P) ↝ n.next.sols(_,P))

Deriving Actor Services handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } (i=0 ⇒ n’= this) && (i>0 ⇒ n’.sols(S,P) ↝ this.sols(_,P)) && (n.sols(S,P) ↝ n.next.sols(_,P)) && immut(n.next) && n.next = n’

Deriving Actor Services handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } (i=0 ⇒ n’= this) && (i>0 ⇒ n’.sols(S,P) ↝ this.sols(_,P)) && (n.sols(S,P) ↝ n.next.sols(_,P)) && immut(n.next) && n.next = n’

Deriving Actor Services handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } (i=0 ⇒ n’= this) && (i>0 ⇒ n’.sols(S,P) ↝ this.sols(_,P)) && (n.sols(S,P) ↝ n’.sols(_,P)) && immut(n.next) && n.next = n’

Deriving Actor Services handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } (i=0 ⇒ n’= this) && (i>0 ⇒ n’.sols(S,P) ↝ this.sols(_,P)) && (n.sols(S,P) ↝ n’.sols(_,P))

Deriving Actor Services handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } (i=0 ⇒ n’= this) && (i>0 ⇒ n.sols(S,P) ↝ this.sols(_,P))

Deriving Actor Services handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } n.sols(S,P) ↝ this.sols(_,P)

Deriving Actor Services handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } n.sols(S,P) ↝ this.sols(_,P)

Deriving Actor Services handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } n.sols(S,P) ↝ this.sols(_,P) ⊨ this.next.sols(S,P) ↝ this.sols(_,P)

Deriving Actor Services handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } n.sols(S,P) ↝ this.sols(_,P) ⊨ this.next.sols(S,P) ↝ this.sols(_,P)

Deriving Actor Services handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } n.sols(S,P) ↝ this.sols(_,P) ⊨ immut(this.next) && this.next.sols(S,P) ↝ this.sols(_,P)

Alternative responses sols sols query_setup ready req sols response sols sols

Alternative Response Messages message sols(seq<Solution> solutions, int packetSize) { if(this.next != null && this.user != null) { seq<Solution> newStore := solutions ++ this.store; if(|solutions| = 0 || |newStore| >= this.nrSolutions) { this.user.response(newStore); } else { this.next.sols([], packetSize); this.store := newStore; } } }

Alternative Response Messages message sols(seq<Solution> solutions, int packetSize) { if(this.next != null && this.user != null) { seq<Solution> newStore := solutions ++ this.store; if(|solutions| = 0 || |newStore| >= this.nrSolutions) { this.user.response(newStore); } else { this.next.sols([], packetSize); this.store := newStore; } } } this.sols(S,P) ↝ this.user.response(_)

Alternative Response Messages message sols(seq<Solution> solutions, int packetSize) { if(this.next != null && this.user != null) { seq<Solution> newStore := solutions ++ this.store; if(|solutions| = 0 || |newStore| >= this.nrSolutions) { this.user.response(newStore); } else { this.next.sols([], packetSize); this.store := newStore; } } } this.sols(S,P) ↝ this.user.response(_)

Alternative Response Messages message sols(seq<Solution> solutions, int packetSize) { if(this.next != null && this.user != null) { seq<Solution> newStore := solutions ++ this.store; if(|solutions| = 0 || |newStore| >= this.nrSolutions) { this.user.response(newStore); } else { this.next.sols([], packetSize); this.store := newStore; } } } this.sols(S,P) ↝ this.user.response(_)

Alternative Response Messages message sols(seq<Solution> solutions, int packetSize) { if(this.next != null && this.user != null) { seq<Solution> newStore := solutions ++ this.store; if(|solutions| = 0 || |newStore| >= this.nrSolutions) { this.user.response(newStore); } else { this.next.sols([], packetSize); this.store := newStore; } } } this.sols(S,P) ↝ this.user.response(_) |

Alternative Response Messages message sols(seq<Solution> solutions, int packetSize) { if(this.next != null && this.user != null) { seq<Solution> newStore := solutions ++ this.store; if(|solutions| = 0 || |newStore| >= this.nrSolutions) { this.user.response(newStore); } else { this.next.sols([], packetSize); this.store := newStore; } } } this.sols(S,P) ↝ this.user.response(_) | this.next.sols(_,P)

Alternative Response Messages message sols(seq<Solution> solutions, int packetSize) { if(this.next != null && this.user != null) { seq<Solution> newStore := solutions ++ this.store; if(|solutions| = 0 || |newStore| >= this.nrSolutions) { this.user.response(newStore); } else { this.next.sols([], packetSize); this.store := newStore; } } } IDEA: introduce this if-condition this.sols(S,P) ↝ this.user.response(_) | this.next.sols(_,P)

Alternative Response Messages message sols(seq<Solution> solutions, int packetSize) { if(this.next != null && this.user != null) { seq<Solution> newStore := solutions ++ this.store; if(|solutions| = 0 || |newStore| >= this.nrSolutions) { this.user.response(newStore); } else { this.next.sols([], packetSize); this.store := newStore; } } } IDEA: introduce this if-condition this.sols(S,P) ↝ this.user.response(_) | this.next.sols(_,P) | ε

Alternative Response Messages message sols(seq<Solution> solutions, int packetSize) { if(this.next != null && this.user != null) { seq<Solution> newStore := solutions ++ this.store; if(|solutions| = 0 || |newStore| >= this.nrSolutions) { this.user.response(newStore); } else { this.next.sols([], packetSize); this.store := newStore; } } } IDEA: introduce this if-condition this.sols(S,P) ↝ this.user.response(_) | this.next.sols(_,P) | ε where old(this.next = null ∨ this.user = null)

Alternative Response Messages message sols(seq<Solution> solutions, int packetSize) { if(this.next != null && this.user != null) { seq<Solution> newStore := solutions ++ this.store; if(|solutions| = 0 || |newStore| >= this.nrSolutions) { this.user.response(newStore); } else { this.next.sols([], packetSize); this.store := newStore; } } } this.sols(S,P) ↝ this.user.response(_) | this.next.sols(_,P) | ε where old(this.next = null ∨ this.user = null) (another local actor service)

Recall: proof of query setup handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } n.sols(S,P) ↝ this.sols(_,P) ⊨ immut(this.next) && this.next.sols(S,P) ↝ this.sols(_,P)

Eliminating alternative responses sols query_setup ready req sols response this.sols(S,P) ↝ this.user.response(_) | this.sols(_,P) | ε where old(this.next = null ∨ this.user = null)

Eliminating alternative responses sols query_setup ready req sols response this.sols(S,P) ↝ this.user.response(_) | this.sols(_,P) | ε where old(this.next = null ∨ this.user = null)

Eliminating alternative responses sols query_setup ready req sols response this.sols(S,P) ↝ this.user.response(_) | this.sols(_,P) | ε where old(this.user = null)

Eliminating alternative responses sols query_setup ready req sols response this.sols(S,P) ↝ this.user.response(_) | this.sols(_,P) | ε where old(this.user = null)

Eliminating alternative responses sols query_setup enough? ready req sols response this.sols(S,P) ↝ this.user.response(_) | this.sols(_,P) | ε where old(this.user = null)

Eliminating alternative responses sols query_setup enough? ready req sols response see the paper! this.sols(S,P) ↝ this.user.response(_) | this.sols(_,P) where localVariant(this) | ε where old(this.user = null)

Eliminating alternative responses sols query_setup enough? ready req sols response see the paper! this.sols(S,P) ↝ this.user.response(_) | this.sols(_,P) where localVariant(this) | ε where old(this.user = null)

Eliminating alternative responses sols query_setup ready req sols response this.sols(S,P) ↝ this.user.response(_) | ε where old(this.user = null)

Eliminating alternative responses sols query_setup ready req sols response this.sols(S,P) ↝ this.user.response(_) | ε where old(this.user = null) ?

Eliminating alternative responses sols query_setup ready req sols response this.req(U,P) ↝ this.sols(_,P) where immut(this.user) && this.user = U && U ≠ null this.sols(S,P) ↝ this.user.response(_) | ε where old(this.user = null)

Eliminating alternative responses sols query_setup ready req sols response this.req(U,P) ↝ this.sols(_,P) where immut(this.user) && this.user = U && U ≠ null this.sols(S,P) ↝ this.user.response(_) | ε where old(this.user = null)

Eliminating alternative responses sols query_setup ready req sols response this.req(U,P) ↝ this.sols(_,P) where immut(this.user) && this.user = U && U ≠ null this.sols(S,P) ↝ this.user.response(_) | ε where old(this.user = null)

Eliminating alternative responses sols query_setup ready req sols response this.req(U,P) ↝ this.sols(_,P) where immut(this.user) && this.user = U && U ≠ null this.sols(S,P) ↝ this.user.response(_) | ε where old(this.user = null)

Eliminating alternative responses sols query_setup ready req sols response this.req(U,P) ↝ U.response(_) | ε where old(U = null && U ≠ null)

Eliminating alternative responses sols query_setup ready req sols response this.req(U,P) ↝ U.response(_) | ε where old(U = null && U ≠ null)

Eliminating alternative responses sols query_setup ready req sols response this.req(U,P) ↝ U.response(_) | ε where false

Eliminating alternative responses sols query_setup ready req sols response this.req(U,P) ↝ U.response(_) | ε where false

Eliminating alternative responses sols query_setup ready req sols response this.req(U,P) ↝ U.response(_)

Eliminating alternative responses sols query_setup ready req sols response this.req(U,P) ↝ U.response(_)

Back to the query setup… handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } this.req(U,P) ↝ U.response(_) derivable for this query manager, at this program point

Back to the query setup… handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } this.req(U,P) ↝ U.response(_) derivable for this query manager, at this program point In particular, by the time of the ready response message …

Back to the query setup… handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } this.req(U,P) ↝ U.response(_) derivable for this query manager, at this program point In particular, by the time of the ready response message … M.query_setup(Q,U’) ↝ U’.ready(M)

Back to the query setup… handler query_setup(Query query, User u) { var n := this; seq<Query> subqueries := // break down query - non-empty for(int i := 0; i < |subqueries|; i := i + 1) { n := spawn QueryWorker(next := n, localQuery := subqueries[i], store := []); } this.next := n; u.ready(this); } this.req(U,P) ↝ U.response(_) derivable for this query manager, at this program point In particular, by the time of the ready response message … M.query_setup(Q,U’) ↝ U’.ready(M) where (M.req(U,P) ↝ U.response(_))

So we’re done (almost…) Derived an actor service characterising responsiveness: Abstracts over workings of protocol, worker actors Combined with user which promises ready… ↝ req… … the property that Ericsson wanted  We built our proof up modularly workers don’t need to know about managers clients don’t need to know about anything (more) M.query_setup(Q,U’) ↝ U’.ready(M) where (M.req(U,P) ↝ U.response(_)) M.query_setup(Q,user) ↝ user.response(_)

Conclusions Actor services: novel specification and proof technique composition, where-clauses, alternatives, … semantics enabling modular proofs Local actor services: base-cases of actor services Lots more in the paper: Hoare Logic for proofs against implementation Obligation assertions as a tool for liveness properties Formal semantics for actor service assertionsInvariants and variants for actor-local state Hierarchical proofs (actor service assumptions) Soundness argument sketch Related and (lots of) Future Work – please ask 

Any questions? sols sols query_setup ready req sols response sols sols M.query_setup(Q,U’) ↝ U’.ready(M) where (M.req(U,P) ↝ U.response(_))