Authors César Sánchez Felipe Gorostiaga
License CC-BY-4.0
HLola: a Very Functional Tool for Extensible Stream Runtime Verification? tifact Ar en t * Complete * AECl Do TAC C S * * st We * onsi Felipe Gorostiaga1,2,3(B) and César Sánchez1 l A * cu m se eu Ev e nt R ed * Easy to * alu 1 at e d IMDEA Software Institute, Madrid, Spain 2 Universidad Politécnica de Madrid, Madrid, Spain 3 CIFASIS, Rosario, Argentina {felipe.gorostiaga,cesar.sanchez}@imdea.org Abstract. We present HLola, an extensible Stream Runtime Verification (SRV) tool, that borrows from the functional language Haskell (1) rich types for data in events and verdicts; and (2) functional features for parametrization, libraries, high-order specification transformations, etc. SRV is a formal dynamic analysis technique that generalizes Runtime Verifica- tion (RV) algorithms from temporal logics like LTL to stream monitoring, al- lowing the computation of verdicts richer than Booleans (quantitative values and beyond). The keystone of SRV is the clean separation between temporal depen- dencies and data computations. However, in spite of this theoretical separation previous engines include hardwired implementations of just a few datatypes, re- quiring complex changes in the tool chain to incorporate new data types. Addi- tionally, when previous tools implement features like parametrization these are implemented in an ad-hoc way. In contrast, HLola is implemented as a Haskell embedded DSL, borrowing datatypes and functional aspects from Haskell, re- sulting in an extensible engine4 . We illustrate HLola through several examples, including a UAV monitoring infrastructure with predictive characteristics that has been validated in online runtime verification in real mission planning. 1 Introduction Runtime Verification [4, 14, 18] is a dynamic technique that studies (1) how to generate monitors from formal specifications, and (2) algorithms to monitor the system under analysis, one trace at a time. Early RV specification languages were based on logics like past LTL [19] adapted to finite traces [5, 10, 15], regular expressions [23], fix-point logics [1], rule based languages [3], or rewriting [21]. Verdicts and many times observa- tions in most of these specification logics are restricted to Booleans, often because most early logics in RV were borrowed from static verification—where decidability is cru- cial. SRV [9,22] attempts to generalize these monitoring algorithms to richer datatypes, including in observations and verdicts. SRV offers declarative specifications where off- set expressions allow accessing streams at different moments in time, including future instants. Most previous SRV developments [9, 11] and their extensions to event-based ? This work was funded in part by the Madrid Regional Government under project “S2018/TCS- 4339 (BLOQUES-CM)”, by Spanish National Project “BOSCO (PGC2018-102210-B-100)”. 4 The tool is available open-source at http://github.com/imdea-software/hlola © The Author(s) 2021 J. F. Groote and K. G. Larsen (Eds.): TACAS 2021, LNCS 12652, pp. 349–356, 2021. https://doi.org/10.1007/978-3-030-72013-1 18 350 F. Gorostiaga and C. Sánchez systems [8,11,12,17] focus on efficiently implementing the temporal engine, promising that new datatypes can be incorporated easily. However, in practice, adding a datatype requires modifying the parser, the internal representation and the runtime system. Con- sequently, existing tools only support a limited hardwired collection of datatypes (typi- cally Booleans and numeric types for quantitative monitoring). In this paper we demonstrate the tool HLola, whose core language is Lola [9], but that enables arbitrary datatypes. HLola is implemented as an embedded DSL in Haskell. Other RV tools implemented as eDSLs include [2, 13] (in Scala), and [24] which implements LTL as an eDSL in Haskell. The main theoretical novelty of HLola is a technique called lift deep embedding, that consists in borrowing types transparently from Haskell and embedding the resulting language back into Haskell (see [7] for an in- troduction to HLola with details of the theoretical underpinnings). In fact, most HLola datatypes were introduced after the temporal engine was completed without requiring any re-implementation. An eDSL enables higher-order functions to describe transfor- mations that produce stream declarations from stream declarations, enabling stream parametrization for free. HLola libraries collect these transformers so new logics like LTL, MTL, etc with Boolean and quantitative semantics can be implemented in a few lines (see Section 2). Haskell type-classes enable simplifiers, which can anticipate the value of an expression without requiring the computation of all its sub-expressions. Implementing these in previous systems requires to re-invent and implement features manually (like macro expansions, etc). HLola even allows specifications as data to im- plement “specifications within specifications” (a feature that allows computing a full auxiliary specification at every instant, useful in simulation and for nested properties). This is used in an UAV scenario to implement Kalman filters [16] as monitors that predict the trajectory of the unmanned aircraft. The output of this monitor is used to anticipate problems (using another monitor) and take preventive planning actions. Stream Runtime Verification in a nutshell SRV generalizes monitoring algorithms to arbitrary data, where datatypes are abstracted using multi-sorted first-order interpreted signatures (called data theories in the Lola terminology). The signatures are interpreted in the sense that every functional symbol f used to build terms of a given type is accom- panied with an evaluation function f (the interpretation) that allows the computation of values (given values of the arguments). A Lola specification hI, O, Ei consists of (1) a set of typed input stream variables I, which correspond to the inputs observed by the monitor; (2) a set of typed output stream variables O which represent the outputs of the monitor as well as intermediate observations; and (3) defining equations, which as- sociate every output y ∈ O with a stream expression Ey that describes declaratively the intended values of y. The set of stream expressions of a given type is built from constants and function symbols as constructors (as usual), and also from offset expres- sions of the form s[k, d] where s is a stream variable, k is an integer number and d is a value of the type of s used as default. For example, altitude[-1,0.0m] repre- sents the value of stream altitude in the previous step of time, with 0.0m as default value to be used at the initial instant. Online efficient algorithms can be synthesized for specifications with (bounded) future accesses [9, 22], where efficiency means that re- sources (time and space) are independent of the length of the trace and can be calculated statically. HLola can be efficiently monitored in a trace-length independent sense [7]. HLola: a Very Functional Tool for Extensible Stream Runtime Verification 351 2 The HLola Tool Fig. 1 shows the software architecture of HLola. We start from an HLola specification, which can borrow datatypes, notation and features from the Haskell language (repre- sented by the red dashed arrow in Fig. 1). A simple translator processes the specification and generates code in the Haskell eDSL. The translator does not fully parse the spec and only preforms simple rewrites, leaving most of the specification unchanged. The resulting code is combined with the HLola engine (developed in Haskell) and compiled into a binary in the target platform. A well-known downside of this approach is that during the second compilation stage, error reports may be rather cryptic. On the other hand, a Haskell expert can write specifications directly in the embedded DSL, which still resembles Lola, to finely tune an HLola specification. The enhanced capabilities of HLola with respect to Lola (streams as data, stream type polymorphism and parametric streams) impact the syntax of the language, which diverges slightly from the syntax of the original Lola. HLola files can either be libraries or specifications: Libraries include HLola code that define streams and facilities to cre- ate streams, and must be declared using library <Name> (where <Name> is the name of the library) on the first line of the HLola file. Specifications first state the format for input and output events as format JSON or format CSV. Source files then can import libraries and stream data manipulation facilities (called theories) with the statements use library <Name> and use theory <Name> respectively. HLola files can also import arbitrary Haskell libraries using the statement use haskell <Name>, and in- clude Haskell code directly anywhere within the blocks delimited between #HASKELL and #ENDOFHASKELL. Specifications then define the input and output streams. An Input stream is declared by its type and name in a line of the form input <Type> <name>, just like in the original Lola language. The syntax of <Type> follows the Haskell no- tation. An Output stream is specified by its type, name and parameters on the left hand side of =, and its defining expression on the right hand side of =: output <TypeConstraints>? <Type> <name> <args>* = <Expr>, where <TypeConstraints> is an optional set of constraints over the polymorphic types handled by the stream (expressed in Haskell notation), and <args> is an optional list of arguments of the form <Type> <name>. We can use define instead of output to define intermediate streams, whose values are not reported by the monitor but can be used by other streams. The defining <Expr> of an output stream allows the use of HLola • complex datatypes Haskell Binary • libraries • functional notation SRV • partial application engine • high order + HLola HLola Embedded Haskell to Binary specification DSL compiler eDSL Fig. 1. Software Architecture of HLola. 352 F. Gorostiaga and C. Sánchez let clauses, where blocks, type annotation, do notation, etc. The access to the value of a stream s at the current instant uses the term s[now] to distinguish it from s, the stream itself (whose type is stream of values). The offset expression that accesses a stream s at a shift of i with default value d is written as s[i|d], as in classic Lola. The symbol ’ is used to lift an object o from the theory as in ’o. We sometimes indicate the arity of the object o being lifted for clarity or to aid the type inference as in 2’o. To improve readability, some operators have been overridden by their lifted version, such as if-then-else. Libraries. The following HLola file defines a library of Past-LTL operators, called LTL, as part of the HLola distribution5 . library LTL use library Utils output Bool historically <Stream Bool p> = p[now] && historically p [-1|’True] output Bool once <Stream Bool p> = p[now] || once p[-1|’False] output Bool since <Stream Bool p> <Stream Bool q> = q[now] || (p[now] && p ‘since‘ q [-1|’False]) output Int nFalses <Stream Bool p> = nFalses p[-1|0] + if p[now] then 0 else 1 output Double percFalses <Stream Bool p> = nFalses p[now] ‘intdiv‘ (instantN[now]) The auxiliary library Utils includes instantN, which stores the current instant num- ber. Stream historically is parametrized by Boolean stream p. Once instantiated, historically p will be true until p becomes false for the first time, and will be false thereafter. This definition uses offsets to define the unrolling, using the constant value true in the first instant, lifted from Haskell as ’True. This library also contains quantitative operators like nFalses, that counts the total number of falsifications up to an instant, and percFalses that calculates the ratio of falsifications. A similar library for MTL includes the parametrized definition of ϕ U(a,b) ψ: output Bool until <(Int,Int) (a,b)> <Stream Bool phi> <Stream Bool psi> = from a where from a | a == b = psi[a|’False] | otherwise = psi[a|’False] || (phi[a|’True] && from (a+1)) Here the parametrized stream until takes the interval (a, b) and the streams ϕ and ψ as parameters. Similarly, the library for Quantitative MTL introduces a parametrized stream to calculate the arithmetic mean of the last k values of a given stream: output Double meanLast <Int k> <Stream Double str> = numr / denom where denom=1’fromIntegral (2’min ’k (instantN[now])) ; numr=sumLast k str [now] which takes as parameters the window size k and the stream str. The denominator is the minimum of k and instantN, converted to Double. The numerator is the sum of the last k values in str. Polymorphosim allows us to generalize this definition to any Haskell type as long as it is Fractional, Equalizable and Streamable, using the following stream signature instead (and the same expression): output (Eq a, Fractional a, Streamable a) => a meanLast <Int k> <Stream a str> 5 All libraries, definitions and examples are available open-source in the GitHub repository and at https://software.imdea.org/hlola/specs.html. HLola: a Very Functional Tool for Extensible Stream Runtime Verification 353 3 Example Specifications In this section we show a collection of HLola specifications to demonstrate the capabil- ities of HLola to define stream based monitors. Temporal Logics. HLola allows us to easily define, in a declarative way, many specifi- cations written in temporal logic. The HLola distribution contains many LTL examples, including a sender/receiver model from [6], and other temporal logics. Consider the fol- lowing MTL property from [20]: (alarm → ([0,10] allClear ∨ [10,10] shutdown)), which includes deadlines between environment events and the corresponding system responses, stating that that an alarm is followed by a shutdown event in exactly 10 time units unless allClear is received. This is defined in HLola as follows: format JSON use library MTL #HASKELL data Event = Alarm | AllClear | ShutDown deriving (Generic,Read,FromJSON,Eq) #ENDOFHASKELL input Event event define Bool allClear = event [now] === ’AllClear define Bool shutdown = event [now] === ’Shutdown define Bool alarm = event [now] === ’Alarm output Bool property = alarm [now] ‘implies‘ (willClear[now] || willShutdown[now]) where willClear = eventually (0,10) allClear willShutdown = eventually (10,10) shutdown Pinescript example. TradingView is an online charting platform for stock exchange, which offers the Pinescript language to query stock time series. Pinescript queries are then run in the company’s servers. We have implemented the indicators of Pinescript in HLola as a library, and we have implementated a trading strategy6 using the HLola Pinescript library. Compared to Pinescript, HLola offers formal semantics, runtime re- source guarantees (time and space) and is much more expressive, for example allowing relational queries that involve multiple stocks (their averages, etc). UAV specifications. We have used HLola also for the online monitoring of several properties of UAVs missions. For example: (1) That the UAV does not fly over for- bidden regions, and (2) that the UAV is in good position when it takes a picture. The input streams of these two specifications consist of the state of the UAV at every in- stant and the onboard camera events to detect when a picture is being captured. This specification imports geometric facilities from theory Geometry2D, and Haskell li- braries Data.Maybe and Data.List. It then defines custom datatypes to retrieve data from the UAV, which are enclosed in a verbatim HASKELL block. The output stream all_ok_capturing assesses that, whenever the vehicle is taking a picture, the height, roll and pitch are acceptable and the vehicle is near the target location. The output stream flying_in_safe_zones reports if the UAV is flying outside every forbid- den region. The output stream depth_into_poly takes the minimum of the distances between the vehicle position and every side of the forbidden region inside which the vehicle is. 6 Available at www.tradingview.com/script/DushajXt-MACD-Strategy 354 F. Gorostiaga and C. Sánchez format JSON use theory Geometry2D use library Utils use haskell Data.Maybe use haskell Data.List #HASKELL data Attitude = Attitude {yaw :: Double, roll :: Double, pitch :: Double} deriving (Show,Generic,Read,FromJSON,ToJSON) data Target = Target {x :: Double, y :: Double, num_wp :: Double} ... data Position = Position {x :: Double, y :: Double, alt :: Double} ... #ENDOFHASKELL input Attitude attitude input Vector2 velocity input Position position input Double altitude input Target target input [[[Double]]] nofly input [String] events_within output Bool all_ok_capturing = capturing [now] ‘implies‘ (height_ok [now] && near [now] && roll_ok [now] && pitch_ok [now]) output Bool flying_in_safe_zones = ’isNothing (flying_in_poly [now]) output (Maybe Double) depth_into_poly = let mSides = ’(fmap polygonSides) (flying_in_poly [now]) distance_from_pos = ’shortestDist (filtered_pos [now]) in 2’fmap distance_from_pos mSides where shortestDist x = minimum.map (distancePointSegment x) define Bool capturing = ... define Double filtered_pos_component <(Position->Double) field> <String nm> = ... define Double filtered_pos_x = filtered_pos_component x "x" [now] define Double filtered_pos_y = filtered_pos_component y "y" [now] define Double filtered_pos_alt = filtered_pos_component alt "alt" [now] define Point2 filtered_pos = ’P (filtered_pos_x [now]) (filtered_pos_y [now]) define Bool near = let target_pos = ’targetToPoint (target [now]) in 2’distance (filtered_pos [now]) target_pos < 1 where targetToPoint (Target x y _) = P x y define Bool height_ok = filtered_pos_alt [now] > 0 define Bool roll_ok = ’(abs.roll) (attitude [now]) < 0.0523 define Bool pitch_ok = ’(abs.pitch) (attitude [now]) < 0.0523 define [Polygon] no_fly_polys = ... define (Maybe Polygon) flying_in_poly = let position_in_poly = ’pointInPoly (filtered_pos [now]) in 2’find position_in_poly (no_fly_polys [now]) Intermediate stream capturing captures whether the UAV is taking a picture (omitted for brevity). The streams filtered_pos_alt and filtered_pos represent the loca- tion and altitude of the UAV filtered to reduce noise from the sensors. We omit the defi- nition of the filter, which is implemented in filtered_pos_component The streams height_ok, roll_ok, and pitch_ok, calculate that the corresponding attitude of the vehicle is within certain boundaries. Finally, the intermediate stream no_fly_polys obtains a set of Polygons from the input forbidden regions (its definition has been omit- ted), and the stream flying_in_poly returns the forbidden region in which the vehi- cle is flying, if any. The artifact attached to this paper includes more UAV specifications, which have been validated in real missions [25]. HLola: a Very Functional Tool for Extensible Stream Runtime Verification 355 References 1. Howard Barringer, Allen Goldberg, Klaus Havelund, and Koushik Sen. Rule-based runtime verification. In Proc. of the 5th Int’l Conf. on Verification, Model Checking and Abstract Interpretation (VMCAI’04), volume 2937 of LNCS, pages 44–57. Springer, 2004. 2. Howard Barringer and Klaus Havelund. Tracecontract: A scala DSL for trace analysis. In Michael J. Butler and Wolfram Schulte, editors, FM 2011: Formal Methods - 17th Interna- tional Symposium on Formal Methods, Limerick, Ireland, June 20-24, 2011. Proceedings, volume 6664 of Lecture Notes in Computer Science, pages 57–72. Springer, 2011. 3. Howard Barringer, David Rydeheard, and Klaus Havelund. Rule systems for run-time mon- itoring: From eagle to ruler. In Oleg Sokolsky and Serdar Taşıran, editors, Runtime Verifica- tion, pages 111–125, Berlin, Heidelberg, 2007. Springer Berlin Heidelberg. 4. Ezio Bartocci and Yliès Falcone, editors. Lectures on Runtime Verification - Introductory and Advanced Topics, volume 10457 of LNCS. Springer, 2018. 5. Andreas Bauer, Martin Leucker, and Chrisitan Schallhart. Runtime verification for LTL and TLTL. ACM Transactions on Software Engineering and Methodology, 20(4):14, 2011. 6. Marco Benedetti and Alessandro Cimatti. Bounded model checking for past LTL. In Proc. of TACAS’03, volume 2619 of LNCS, pages 18–33. Springer, 2003. 7. Martı́n Ceresa, Felipe Gorostiaga, and César Sánchez. Declarative stream runtime verifica- tion (hlola). In Bruno C. d. S. Oliveira, editor, Programming Languages and Systems, pages 25–43, Cham, 2020. Springer International Publishing. 8. Lukas Convent, Sebastian Hungerecker, Martin Leucker, Torben Scheffel, Malte Schmitz, and Daniel Thoma. TeSSLa: Temporal stream-based specification language. In Proc. of SBMF’18, volume 11254 of LNCS. Springer, 2018. 9. Ben D’Angelo, Sriram Sankaranarayanan, César Sánchez, Will Robinson, Bernd Finkbeiner, Henny B. Sipma, Sandeep Mehrotra, and Zohar Manna. LOLA: Runtime monitoring of syn- chronous systems. In Proc. of the 12th Int’l Symp. of Temporal Representation and Reason- ing (TIME’05), pages 166–174. IEEE CS Press, 2005. 10. Cindy Eisner, Dana Fisman, John Havlicek, Yoad Lustig, Anthony McIsaac, and David Van Campenhout. Reasoning with temporal logic on truncated paths. In Proc. of the 15th Int’l Conf. on Computer Aided Verification (CAV’03), volume 2725 of LNCS, pages 27–39. Springer, 2003. 11. Peter Faymonville, Bernd Finkbeiner, Malte Schledjewski, Maximilian Schwenger, Marvin Stenger, Leander Tentrup, and Torfah Hazem. StreamLAB: Stream-based monitoring of cyber-physical systems. In Proc. of the 31st Int’l Conf. on Computer-Aided Verification (CAV’19), volume 11561 of LNCS, pages 421–431. Springer, 2019. 12. Felipe Gorostiaga and César Sánchez. Striver: Stream runtime verification for real-time event-streams. In Proc. of the 18th Int’l Conf. on Runtime Verification (RV’18), volume 11237 of LNCS, pages 282–298. Springer, 2018. 13. Klaus Havelund. Rule-based runtime verification revisited. Int. J. Softw. Tools Technol. Transf., 17(2):143–170, 2015. 14. Klaus Havelund and Allen Goldberg. Verify your runs. In Proc. of VSTTE’05, LNCS 4171, pages 374–383. Springer, 2005. 15. Klaus Havelund and Grigore Roşu. Synthesizing monitors for safety properties. In Proc. of the 8th Int’l Conf. on Tools and Algorithms for the Construction and Analysis of Systems (TACAS’02), volume 2280 of LNCS, pages 342–356. Springer-Verlag, 2002. 16. Rudolph Emil Kalman. A new approach to linear filtering and prediction problems. Trans- actions of the ASME–Journal of Basic Engineering, 82(Series D):35–45, 1960. 17. Martin Leucker, César Sánchez, Torben Scheffel, Malte Schmitz, and Alexander Schramm. TeSSLa: Runtime verification of non-synchronized real-time streams. In Proc. of the 33rd Symposium on Applied Computing (SAC’18). ACM, 2018. 356 F. Gorostiaga and C. Sánchez 18. Martin Leucker and Christian Schallhart. A brief account of runtime verification. J. Logic Algebr. Progr., 78(5):293–303, 2009. 19. Zohar Manna and Amir Pnueli. Temporal Verification of Reactive Systems. Springer-Verlag, 1995. 20. Joël Ouaknine and James Worrell. Some recent results in metric temporal logic. In Proc. of FORMATS’08, volume 5215 of LNCS, pages 1–13. Springer, 2008. 21. Grigore Roşu and Klaus Havelund. Rewriting-based techniques for runtime verification. Automated Software Engineering, 12(2):151–197, 2005. 22. César Sánchez. Online and offline stream runtime verification of synchronous systems. In Proc. of the 18th Int’l Conf. on Runtime Verification (RV’18), volume 11237 of LNCS, pages 138–163. Springer, 2018. 23. Koushik Sen and Grigore Roşu. Generating optimal monitors for extended regular expres- sions. In Oleg Sokolsky and Mahesh Viswanathan, editors, Electronic Notes in Theoretical Computer Science, volume 89. Elsevier, 2003. 24. Volker Stolz and Frank Huch. Runtime verification of concurrent haskell programs. Electron. Notes Theor. Comput. Sci., 113:201–216, 2005. 25. Sebastián Zudaire, Felipe Gorostiaga, César Sánchez, Gerardo Schneider, and Sebastián Uchitel. Assumption monitoring using runtime verification for UAV temporal task plan executions. Under submission, 2020. 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 per- mits 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 chapter are included in the chapter’s Creative Commons license, unless indicated otherwise in a credit line to the material. If material is not in- cluded in the chapter’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.