Online Detection of Effectively Callback Free Objects with Applications to Smart Contracts

SHELLY GROSSMAN, Tel Aviv University, Israel ITTAI ABRAHAM, VMware Research, USA GUY GOLAN-GUETA, VMware Research, USA YAN MICHALEVSKY, Stanford University, USA NOAM RINETZKY, Tel Aviv University, Israel MOOLY SAGIV, Tel Aviv University, Israel and VMware Research, USA YONI ZOHAR, Tel Aviv University, Israel Callbacks are essential in many programming environments, but drastically complicate program understanding and reasoning because they allow to mutate object’s local states by external objects in unexpected fashions, thus breaking modularity. The famous DAO bug in the cryptocurrency framework Ethereum, employed callbacks to steal $150M. We define the notion of Effectively Callback Free (ECF) objects in order toallow callbacks without preventing modular reasoning. An object is ECF in a given execution trace if there exists an equivalent execution trace without callbacks to this object. An object is ECF if it is ECF in every possible execution trace. We study the decidability of dynamically checking ECF in a given execution trace and statically checking if an object is ECF. We also show that dynamically checking ECF in Ethereum is feasible and can be done online. By running the history of all execution traces in Ethereum, we were able to verify that virtually all existing contract executions, excluding these of the DAO or of contracts with similar known vulnerabilities, are ECF. Finally, we show that ECF, whether it is verified dynamically or statically, enables modular reasoning about objects with encapsulated state. CCS Concepts: • Theory of computation → Program analysis; • Software and its engineering → Dynamic analysis; Additional Key Words and Phrases: Program analysis, Modular reasoning, Smart contracts

1 INTRODUCTION The theme of this paper is enabling modular reasoning about the correctness of objects with encapsulated state. This is inspired by platforms like Ethereum [Wood 2016] that facilitate execution of Smart Contracts [Szabo 1997] on top of a blockchain-based distributed ledger [Nakamoto 2008]. A key property in Ethereum Smart Contracts is the lack of global mutable shared state, in contrast to common standard programming environments such as and Java. A smart contract is analogous to an object with encapsulated state. However, the Ethereum blockchain, and many other dynamic environments, implement event- driven programming using callbacks. These callbacks are necessary for functionality, but can compromise security. For example, the famous bug in the DAO contract exploited callbacks to steal $150M [Daian 2016]. Indeed, callbacks may break modularity which is essential for good programming style and extendibility. In the context of Blockchain, modularity is even more important since contracts are contributed by different sources, some of which may be malicious. Accordingly, the bug intheDAO allowed an adversarially crafted contract to mutate the DAO’s state by calling back to it. The DAO contract, that implemented a crowd-funding platform, was attacked by a ‘callback loop-hole’ (to be precisely described below). This attack, the recovery from which required a controversial hard-fork of the blockchain,1 exhibits a vulnerability that is peculiar to decentralized

1A hard fork can be thought of as taking an agreed history of transactions, and manually change it. consensus systems, like Ethereum: in such systems, a buggy contract cannot be updated or fixed (except for extreme measures like hard-forking), which makes validation and verification of smart contracts of even greater importance for this application. Effectively Callback-Free Objects. We identify a natural generic correctness criteria for objects which enables modular reasoning in environments with local-only mutable states, and expect most correct objects to satisfy this requirement. Informally, if an object o calls another object o′, and the execution of o′ calls o again, this second call to o is defined as a callback. The main idea isto allow callbacks in o only when they cannot affect the serial non-interruptible behavior of o. Thus, such callbacks can be considered harmless and do not affect the set of local reachable states ofthe object o. In particular, the behavior of such objects is independent of the client environments and of other objects. It is possible to reproduce all behaviors of the object using a most general client and without analyzing external objects. We say that an execution is Dynamically Effectively Callback Free (dECF) when there exists “an equivalent” execution without callbacks which starts in the same state and reaches the same final state. By equivalent, we refer to the behavior of a particular object as an external observer may perceive. We say that an object is Statically Effectively Callback Free (sECF) when all its possible executions are dynamically ECF. We do not distinguish between dynamic and static ECF when the context is clear. Both definitions are useful. Dynamic ECF in particular is applicable tothe blockchain environment, since static ECF is undecidable in the general case. We ran experiments on Ethereum, proving that checking dynamic ECF is inexpensive, and thus can be done efficiently in-vivo. This, combined with Ethereum’s built-in rollback feature, would have allowed to prevent the DAO bug from occurring, without invalidating legitimate executions. (In fact, we found just one such legitimate non-ECF contract, discussed in Section9). We show that the vulnerable DAO contract is non-ECF while no non-ECF executions are detected after applying the suggested corrections to it. Notice that the ECF notion is similar to the notion of atomic transactions in concurrent systems. Indeed, despite the fact that contract languages do not usually support concurrency, modularity and callbacks require similar kind of reasoning. The ECF property’s usefulness is not limited to bug-finding; once ECF is established, it canbe served to simplify reasoning on the object in isolation of other objects: We show that the set of reachable local states in ECF objects can be determined without considering the code of other objects and thus enable modular reasoning. This modular reasoning can be performed automatically using abstract interpretation e.g., as suggested in Logozzo[2009] or by using deductive verification which is supported by Dafny [Leino 2010]. We demonstrate this by verifying an interesting invariant of the DAO contract. (See Section2). Online Detection of ECF executions. A naïve detection of dECF may be costly because of the need to enumerate subexecution traces. Therefore, we develop an effective polynomial online algorithm for checking if an execution is ECF. The main idea is to detect conflicting memory accesses and utilize commutativity in an effective manner. We integrated the algorithm into the Ethereum Virtual Machine (EVM) [Wood 2016]. We ran the algorithm on all executions kept in the Ethereum blockchain until 23 June 2017, and demonstrate that: (i) the vulnerable DAO contract and other buggy contracts are non-ECF. (ii) very few correct contracts are non-ECF, (iii) callbacks are not esoteric and are used in many contracts, and (iv) the runtime overhead of our implementation is negligible and thus can be integrated as an online check. This online detection can thus be used to prevent incidents like the theft from the DAO at the cost of slightly more restricted form of programming. As far as we are aware, our tool is also the most precise and effective tool for finding such vulnerable behaviors due to callbacks. We compared it to the Oyente tool [Luu et al. 2016; Melonport 2017], by giving it both ECF and non-ECF contracts based on the DAO object (Figure1). We found that it has false positives, as it detects a ‘reentrancy bug’ (the common name of the DAO vulnerability in the blockchain community) for any one of the fixes that render our example contract ECF. Decidability of sECF for objects. We also consider the problem of checking sECF algorithmically. Obviously, since modern contract languages, such as Solidity [Ethereum Foundation 2017b], are Turing complete, checking if a contract is ECF is undecidable. We show that checking that a contract is sECF in a language with finite local states is decidable. This is interesting since many contracts only use small local states or maps with uniform data independent accesses. Technically, this result is non-trivial since the nesting of contract calls is unbounded, and since ECF requires reasoning about permutations of nested invocations. The reason for the decidability is that non-ECF executions which occur in high depth of nesting must also occur in depth 2. Main Results. Our results can be summarized as follows: (1) We define a general safety property, called ECF, for objectssECF ( ) and executions (dECF). Our definition is inspired by the Blockchain environment but it may also be useful forother environments with encapsulated states, such as Microservices. (2) We show that objects with encapsulated data, under the assumption that they satisfy ECF, can be verified using modular reasoning in a sound manner. (3) A stronger notion of ECF, based on conflict-equivalence, enabling efficient verification of dECF in real-life environments, and for which sECF is decidable for programs with finite state and unbounded stack. (4) A polynomial time and space algorithm for online checking of dECF and prototype imple- mentation of it as a dynamic monitor of dECF, built on top of an Ethereum client. (5) Evaluation of the algorithm on the entire history of the Ethereum blockchain (both main and ‘Classic’ forks, see Section9). The monitor detects true bad executions (the infamous DAO and others) as non-ECF, and has near-zero false positives. Based on this result, it can be inferred that, in practice, most non-ECF executions correspond to bad executions. We also show that our monitor has a very small runtime overhead. By retroactively running the dECF monitor on the available history, we were able to prove its effectiveness in preventing the exploitation of the vulnerability in the DAO, and even more importantly, the feasibility of leveraging it in other applications, e.g., simplifying modular contract verification.

2 OVERVIEW This section provides some necessary background and an informal overview of our approach.

2.1 The DAO Bug Figure1 shows pseudocode illustrating the vulnerability in the DAO. 2 The contract stores a credit for each object, as well as the current balance.3 The credit represents individual investments per object. To align with the Ethereum terminology, the unit of currency represented by credit and balance is called ether. The contract maintains a representation invariant, where the sum of the credits equals to the current balance, i.e.,

Σo ∈dom(credit)credit[o] = balance (1)

2DAO is acronym for decentralized autonomous organization, and its purpose is to facilitate voting on proposals and on investments by the owners of the DAO. 3In programming languages like Solidity, balance is a predefined field of every contract, maintained by the runtime system. We write it explicitly for clarity. Object DAO Map credit int balance Invariant (sum o: credit[o]) = balance

Method withdrawAll(Object o) Method deposit(Object o, int amount) 2: if (oCredit > 0) 6: credit[o] += amount // 2.5: credit[o] = 0 7: this.balance += amount 3: this.balance -= oCredit 4: o.pay(oCredit) 5: credit[o] = 0

Fig. 1. A contract illustrating the DAO bug. The representation invariant may be violated by callbacks from malicious contracts. Line 2.5 fixes the bug.

Object GoodClient Object Attacker Object Dao, int balance Object Dao, bool stop, int balance Method init(Object dao) Method init(Object dao) 1: this.Dao = dao 1: Dao = dao Method pay(int profit) 2: stop = false 2: this.balance += profit Method pay(int profit) Method depositCredit(Object dao, int amount) 3: this.balance += profit 3: Dao.deposit(this, amount) 4: if (!stop) Method getCredit(Object dao) 5: stop = true 4: Dao.withdrawAll(this) 6: Dao.withdrawAll(this) 7: stop = false

(a) An innocent client using the DAO object without (b) A snippet of an Attacker object. It is stealing violating its representation invariant. money from the DAO object by violating its repre- sentation invariant.

Fig. 2. An innocent and a malicious client using the DAO object

The contract offers two methods for manipulating states: deposit for depositing money and withdrawAll for withdrawing all available funds of a specific object. Figure 2a shows a simple client illustrating the expected usages of the DAO object. Figure 2b shows a simple attack on the DAO object. The code callbacks to the DAO method withdrawAll to steal money. Figure3 depicts a concrete trace of attacking the DAO assuming that the DAO’s initial balance is 200 ether. We reached that state after a GoodClient object and an Attacker object deposited each 100 ether. In the first call to withdrawAll, the attacker will get the amount he invested originally in the attack (100 ether). The DAO then calls to the Attacker object’s pay method, which increases the attacker’s balance by 100 ether, and calls withdrawAll again. The pay method is designed to call withdrawAll at most once in a trace by updating the stop variable, and avoid infinite recursion.4 The code of withdrawAll in the second run will transfer an additional 100 ether from the DAO object to the attacker. In the end of the trace, the DAO was depleted of its funds completely, and the attacker managed to illegitimately receive the funds that belonged to GoodClient.

4For clarity, we avoid technical discussion of the semantics of executions and exceptions in Ethereum/Solidity, to allow us to focus on the ECF property. D.c[G] = 100 D.c[A] = 100 w { read D.c[A] = 100 p { A.b = 100 w { read D.c[A] = 100 p { A.b = 200 D.b = 200 / / / / 1 D.b = 100 2 A.s = true 3 D.b = 0 4 A.s = true A.b = 0 A.s = false

5 p } D.c[G] = 100 D.c[A] = 0 t w } p } w } D.c[A] = 0 / A.s = false / D.c[A] = 0 / D.b = 0 6 7 8 A.b = 200 A.s = false

Fig. 3. A trace of calls illustrating an attack on the DAO. Nodes are labeled by local changed states and edges are labeled by actions and by the corresponding order in the original trace. D denotes the DAO, G denotes a GoodClient and A is an Attacker object. w denotes the withdrawAll operation and p denotes the pay operation. b is a shorthand for balance, c is a shorthand for credit, and s is a shorthand for stop.

D.c[G] = 100 D.c[G] = 100 D.c[A] = 100 D.c[A] = 0 w { D.c[A] = 0 p { A.b = 100 w { w } p } w } D.b = 200 / / / read D.c[A] = 0 / A.s = false / / D.b = 100 1 D.b = 100 2 A.s = true 3 4 5 6 A.b = 0 A.b = 100 A.s = false A.s = false

D.c[G] = 100 D.c[G] = 100 D.c[A] = 100 D.c[A] = 0 w { D.c[A] = 0 w } p { A.b = 100 w { w } p } D.b = 200 / / / / read D.c[A] = 0 / A.s = false / D.b = 100 1 D.b = 100 6 2 A.s = true 3 4 5 A.b = 0 A.b = 100 A.s = false A.s = false

Fig. 4. Two traces of calls illustrating the original and callback-free versions of a failed attack on the ECF version of the DAO.

2.2 Effectively Callback Free Contracts In principle, semi-automatic program verification and abstract interpretation can be used to verify the absence of malicious attacks like the one in the Attacker object. However, this requires reasoning about the whole code.5 This paper advocates a different solution by exploring modularity. The idea is to require stronger conditions from the contracts which prevent the need to reason about other objects at all. Specifically, we define the notion of effectively callback free (ECF) objects. Our definition is inspired by Blockchain contracts but is applicable to enforce modularity in other environments with local states. We say that an execution of an object with an initial state s0 and final state s is Dynamically Effectively Callback Free (dECF) when there exists “an equivalent” execution of the contract without callbacks which starts in the same initial state s0 and reaches the final state s. We say

5In the case of Ethereum, it is in fact impossible to reason about the whole code, as new contracts can be added at any time, and these contracts could interact with the contract being checked. that an object is Statically Effectively Callback Free (sECF) when all its possible executions are effectively callback free. The DAO object is not ECF. For example, the trace depicted in Figure3 cannot be reproduced without callbacks to reach the same state. In contrast, the fix to the DAO object by uncommenting line 2.5 and deleting line 5 makes the contract ECF. This contract is now ECF since all its traces can be reordered to avoid callbacks. For example, Figure4 shows a trace of an attempt to perform an attack similar to the attack in Figure3 and its corresponding reordering that avoids callbacks. Note, that in the reordered trace, withdrawAll did not execute line 4. Omitting calls is allowed for the sake of proving an execution is ECF, as our goal is to be able to reproduce, assuming there are no callbacks, the same behaviors that are feasible with callbacks.

2.3 Online ECF Detection It is possible to check in a naïve way that an execution is ECF by recording the trace and checking the ECF property at the end of the execution, by enumerating all possible permutations. However, this is costly both in space and in time, since the number of permutations grows exponentially with the size of the trace. In particular, it is hard to see if such a solution can be integrated into a virtual machine. In order to obtain a feasible online algorithm, we check a stronger requirement than ECF, which is inspired by conflict serializability of database transactions. The main idea is to explore commuta- tivity of operations for efficient online checking of a correctness condition which guarantees that the callback-free trace results in the same state as the original trace. Consider a trace π with potential callbacks and a reordered trace π ′ which does not include callbacks. π ′ is not necessarily feasible, unless we permit to ignore external calls by objects and force the clients to perform these calls instead. We say that π and π ′ are conflict equivalent if every pair of conflicting read/write operations in π appear in the same order in π ′. Operations conflict when they are not commutative. Commutativity is mechanically checked by comparing the read and the write sets of operations, and forbidding intersection of read/write conflicts. For example, in Figure3, the read operation of D.c[A] in the withdrawAll action labeled 1 (lines 1-3) does not commute with the write operation of D.c[A] in the withdrawAll action labeled 5 (line 5). However, the top trace in Figure4, depicting a trace of the ECF version of DAO, the operations in the withdrawAll action labeled 3 (lines 1-2) commute with the operations in the withdrawAll action labeled 6, which has an empty read and write sets (no code was executed since line 5 was deleted). The information regarding commutativity of different subtraces is used to build a constraint graph on the ordering of object invocations. When this constraint graph contains no cycles, it is possible to perform topological sort to find a concrete callback-free trace. A full description of the algorithm and its complexity is available in Section8. We integrated this algorithm into the EVM (the Ethereum Virtual Machine) and applied it to all available executions in the blockchain. The results are summarized in Section9. They indicate that the vast majority of non-ECF executions come from erroneous contracts. They also indicate that the runtime overhead of our instrumentation is neglectable. From these encouraging results, we concluded that if the ECF check was part of the Ethereum protocol, it could have prevented the vulnerability in the DAO from being exploited. Its clearly beneficiary for an environment like Ethereum, which handles sensitive financial transactions, and in which code is virtually impossible to upgrade.

2.4 Deciding ECF Contracts We also investigated the possibility to verify at compile-time that a contract is ECF (the sECF property). In general, this is undecidable, since languages such as Solidity, a high-level front-end to def c ∈ PCmd = x B e | F B x | x B F | assert(b) | x B o(e) | skip | enter | return C ∈ Cmd def= c | C ; C | if b then C else C | whileb do C K ∈ Contract def= k : f enter var x C return

Fig. 5. Syntax.

EVM bytecode, are Turing-complete. However, we show that for contracts with finite local states, checking ECF is decidable. This result is non-trivial as the model allows for an unbounded stack length. The decision procedure devised provides insight on additional techniques for checking ECF in practice.

2.5 Verifying Properties of ECF Contracts In this paper, we show that reasoning about ECF contracts can be performed in a modular fashion. The local reachable states of an ECF contract are only affected by the code of the contract, and cannot be changed by external contracts. This is useful for program verification and program analysis, treating external calls as non- deterministic operations that may return an arbitrary value, but cannot change the local state. We utilized this property using Dafny [Leino 2010], to verify correctness of the revised DAO object from Figure1 (including line 2.5, excluding line 5). When doing so, we ignored the call in line 4, because the return value was not used. We provide a deeper discussion on verifying this example using Dafny in Section7.

2.6 Summary of the Rest of This Paper The paper is organized as follows: In Section3 we formally present the syntax and semantics of our programming language for contracts, called SMAC. Notions of equivalence are presented in Section4. The ECF property and its different ‘flavors’ (dynamic vs. static, and for different equivalence notions) are presented in Section5. We discuss decidability results for ECF in Section6. Section7 shows the application of the ECF property to achieve modular object-level analysis. The algorithm for online verification of dECF is given in full in Section8. We discuss our experimental results obtained by running the algorithm on the Ethereum blockchain in Section9. Related work is provided in Section 10 and we conclude in Section 11.

3 PROGRAMMING LANGUAGE We formalize our results for SMAC, a simple imperative object-based programming language with pass-by-value parameters with integer-typed local variables and data members (fields). For simplicity, and without loss of generality, every method has a single formal parameter named arg and returns a value by assigning it to a designated variable ret. Even though we present our theoretical development for contracts in SMAC, for readability we use a Java-like notation in our examples, which can be easily desugared.

3.1 Syntax Figure5 defines the syntax of SMAC. We assume infinite syntactic domains of k ∈ Cnt, f ∈ Fld, and x ∈ Var contract identifiers, field names, and variable identifiers, respectively. A contract K is identified by a (unique) contract identifier k, and contains a sequence of field definitions f and a (single) nameless contract method. The contract method is comprised of a sequence of local variable definitions x and a command C ∈ Cmd. C may be a primitive command c ∈ PCmd or ρ ∈ Reg = Var ⇀fin Z Local states Γ ∈ Stack = Frame Stacks ψ ∈ Heap = Fld →fin Z Object states σ ∈ Store = Cnt ⇀fin Heap Stores γ ∈ Frame = Cnt × Cmd × Reg Frames s ∈ State = Stack × Store States

Fig. 6. Semantic domains.

⟨ϵ, σ⟩ ⇒ ⟨(o, κ(o), [arg 7→ n]), σ⟩ ⟨(o, return, ρ), σ⟩ ⇒ ⟨ϵ, σ⟩ ⟨(o, x B o′(e), ρ)· γ, σ⟩ ⇒ ⟨(o′,κ(o′), [arg 7→ ρ(e)]) · (o, x B res, ρ)· γ, σ⟩ ⟨(o′, return, ρ′)·(o, c, ρ)· Γ, σ⟩ ⇒ ⟨(o, c, ρ[res 7→ ρ′(ret)]) · Γ, σ⟩

Fig. 7. Operational semantics with a context κ. ρ is naturally extended for expressions over variables in LVar. We denote o ∈ dom(σ),n ∈ N. a compound command, i.e., a sequential composition of commands, a conditional, or a loop. A primitive command c ∈ PCmd may be either an assignment of an expression e to a local variable x (x B e), an assignment of the value of a local variable x to a field F (F B x), an assignment of the value of a field F to a local variable x (x B F), an assert command (assert(b)), a call to a contract method with a single argument e, keeping the returned value in a local variable x (x B o(e)), or a skip command. Each contract has a single method, thus methods are not named, and may be colloquially referred to using the name of their contract. Without loss of generatility, we assume that no two contracts contain a field with the same name. In the following, we use the terms ‘contract’ and ‘object’ interchangeably.

3.2 Semantics SMAC has a rather mundane stack-based operational semantics, which handle method calls using a stack of activation records (frames), and uses a store to record the values stored in object fields. We refer to a state in which the stack is empty as a quiescent state and to a non-quiescent state as an active state. Once the execution reaches a quiescent state, any object method may start running. We refer the reader’s attention to three important points: (i) contract states are encapsulated: A contract o can only access its own fields, (ii) local variables are private to their invocation, and (iii) once a contract method is invoked, the semantics is deterministic. We denote the code context (context for short) which provides the code of every called object by κ ∈ Cnt ⇀f in Cmd, i.e., κ(o) denotes the code of object o. States. Figure6 defines the semantic domains. A state s = ⟨Γ, σ⟩ is a pair comprised of a (possibly empty) stack of frames Γ ∈ Stack and a store σ ∈ Store, denoted by Γ(s) = Γ and σ(s) = σ, respectively. The depth of a state s, denoted by Depth(s), is the number of elements in its stack, i.e., Depth(s) = |Γ(s)|. We denote the top of the stack in an active state s = ⟨Γ, σ⟩ by top(s) = Γ(1). Intuitively, top(s) contains the local state of the active (i.e., currently executing) contract method, while the other frames record the locals states of pending calls to contract methods. A frame γ = (o, c, ρ) records the local state of (a call to the contract method of) an object. Formally, γ is a triple comprised of an object identifier, denoted by o(γ ) = o, a command, denoted by C(γ ) = c, which the method needs to execute, and a local environment ρ ∈ Reg, denoted by ρ(γ ) = ρ, which assigns values to the invocation’s local variables. A store σ ∈ Store is a mapping from a finite number of object identifiers to their object state. Transition relations. We formalize the semantics of our programming language using a transition relation.A transition is a pair τ = (s,s ′) ∈ Tr ⊆ State × State comprised of a source state s, denoted by src(τ ), and target state s ′, denoted by trg(τ ). For clarity, we sometimes write a τ = (s,s ′) as ′ s ⇒ s . We denote the active object of the transition by o(τ ) = o(top(src(τ ))), or omain if it starts in a quiescent state. We denote by c(τ ) ∈ PCmd the primitive command that justifies the transition. The meaning of primitive and compound commands is standard, and thus omitted. We mention that primitive commands can only use local variables taken from the top stack frame, and that only the fields of the active object can be accessed. Figure7 defines meaning of method calls and returns. When an object o is called from a quiescent state, a new stack frame is pushed to the currently empty stack. The frame determines that the active object is o, the command executing is the code κ(o) of o, and the local environment for the invocation is the assignment of the value of n to arg. The last command in κ(o) is always a return, after which the frame is popped, leading to a quiescent state. When a call x B o′(e) is made from an active state, a new stack frame is pushed as in the previous case. We note that the local environment is initialized by assigning to arg the value of e in the local environment belonging to the caller, ρ(e). To handle retrieval of the return value from the callee, the command in the caller is modified to assign to x the value of a specially designated variable res. When the callee invocation of o′ finishes, the command in the top frame is return and we let ρ′ denote the local environment of the callee. The control transfers back to the caller object o, and the value of res is set to be the value of ret in ρ′. The assigned value of res is then automatically assigned to x, as determined by the operational semantics of the call. The primitive command associated with a call is enter, and with a return is return. Executions. An execution π = π(1) ... π(|π |) is a finite sequence of transitions coming from Tr. An execution π is well-formed if the target state of every transition is the source state of the following one, i.e., i ∈ {2..|π |}. trg(π(i − 1)) = src(π(i)). For clarity, we sometimes write an ∀ execution π as π = s1 ⇒ s2 ⇒ · · · sn. We use κ ⊢ π to denote that an execution π takes objects’ code from context κ. We omit the context when no confusion is likely. We say that a transition τ appears in a π, denoted by τ ∈ π, if π = _ · τ · _. We say that a state s appears in a π, denoted by s ∈ π, if there is a transitionτ ∈ π such that s ∈ {src(τ ), trg(τ )}. We denote the sets of transitions and states that appear in an execution π by States(π) and Transitions(π), respectively. An execution π ′ is a subexecution of an execution π, denoted by π ′ ⊑ π, if it is a subsequence of π. We denote the first and last states of a non-empty execution π by src(π) = src(π(1)) and trg(π) = trg(π(|π |)). We say that π = τπ ′τ ′ is a complete execution if src(π) and trg(π) are quiescent states and π ′ contains only active states. A run is a concatenation of complete executions executed in the same code context κ, By abuse of notation, we use π to denote runs as well as executions. In case we want to make the code context κ of the run explicit, we write κ ⊢ π. The minimal and maximal depths of a non-empty execution π, denoted by minDepth(π) = min{Depth(s) | s ∈ States(π)} and maxDepth(π) = max{Depth(s) | s ∈ States(π)} are the minimal, respectively, maximal depths of any of the states it contains. A well formed execution π ′ is an invocation in an execution π if there exist transition τ and τ ′ such that π = _·τ ·π ′·τ ′·_, where Depth(src(τ )) = Depth(trg(τ ′)) and minDepth(π ′) = Depth(src(τ ))+1. We refer to Depth(trg(τ )) as the depth of the invocation π ′ and denote it by Depth(π ′). Note that according to this definition, the depth of an invocation that results from calling a contract method on a quiescent state is one. Traces. We define an event as a pair e = (o, a), consisting of an object o, and a primitive command a. Each transition τ can be transformed to an event by e(τ ) = (o(τ ),c(τ )). The object and primitive command of an event are can be retrieved with o(e) and a(e), respectively. A trace is a sequence of events, denoted by T . The trace matching an execution π is received by point-wise application of e(·) on all the transitions in π, denoted T (π). We denote by T |o the maximal subsequence of T comprised of events whose object is o.

4 EXECUTION EQUIVALENCE We define two notions of equivalence of runs (sequences of complete executions) with respect to a given (arbitrary) object o: final-state equivalence and conflict equivalence.

4.1 Object-Final-State Equivalence

Definition 4.1. Runs κ1 ⊢ π1 and κ2 ⊢ π2 are object-final-state equivalent for an object o, denoted o by κ1 ⊢ π1 ≃FS κ2 ⊢ π2, if their respective first and last states have the same store for o, and their code contexts agree on o: o κ1 ⊢ π1 ≃FS κ2 ⊢ π2 ⇐⇒ σ(src(π1))(o) = σ(src(π2))(o) ∧ σ(trg(π1))(o) = σ(trg(π2))(o) ∧ κ1(o) = κ2(o)

Remark 4.2. Note that in Definition 4.1 it may be that κ1 , κ2 as long as κ1 and κ2 map o to the same code.

4.2 Object Conflict-Equivalence Conflicts. Two primitive commands a and a′ conflict, denoted by Conflict(a, a′), if both access the same field and at least one of these accesses is awrite. Remark 4.3. Recall that we assume that object states are comprised of integer-typed data members (fields); thus it is possible to detect the heap locations they access from the (syntactic) primitive commands that they execute. Furthermore, recall that different objects contain different fields andan object cannot directly access the fields of another; thus if two primitive commands conflict thenthey must be executed by the same active object. Modular Well-Formed Executions. We extend the definition of well-formed executions to modular well-formed executions, which allow to replace the subexecution resulting from a method invocation x B o′(e) by an assignment of arbitrary value to x. We refer to such an (implicit) transition as a havoc transition. Intuitively, a havoc transition allows to safely overapproximate the only effect that an object o may observe from the invocation of a method on an object o′. Definition 4.4. A havoc transition, denoted by s s ′, is a pair of states ⟨s,s ′⟩ ∈ State × State such that s = ⟨(o, x B o′(e), ρ)· Γ, σ⟩ and s ′ = ⟨(o, done, ρ[res 7→ n]) · Γ, σ⟩ for any values of o, o′, e, ρ, Γ, σ and n. Definition 4.5. A modular well-formed execution is a finite sequence of transitions coming from Tr such that for any consecutive transitions τ1τ2 it contains, the target state of τ1 and the source state of τ2 are either (i) equal, i.e., trg(τ1) = src(τ2), or (ii) induce a havoc transition, trg(τ1) src(τ2). By abuse of notations, we use π to denote modular well-formed executions too. A sequence of transitions π is a complete modular well-formed run if it is modular well-formed and its first and last states are quiescent. Such a run is a complete modular well-formed execution if, in addition, all other states are active. Projected Executions. We define what is the projection of an execution on an object, called projected execution. The definition readily generalizes to any sequence of transitions.

Definition 4.6. Let π be an execution. The projected execution of π on o, denoted by π |o, is the subsequence of π comprised of the transitions whose active object is o. Lemma 4.7. For any execution π and object o it holds that T (π |o) = T (π)|o. It will be useful in the following sections to consider modular well-formed executions yielded by a projection on an object o. The following proposition states that it is possible to reverse that projection, namely, to find a minimal well-formed execution that, when projected, yields the modular well-formed execution we started with. Proposition 4.8. Let κ ⊢ π be a modular well-formed execution where all transitions have the same active object o. Then there is a context κ′ such that κ′(o) = κ(o) and an execution κ′ ⊢ π ′ such that T (π) is a subsequence in T (π ′) and κ′ ⊢ π ′ is well-formed. In addition, such an execution κ′ ⊢ π ′ ′ is minimal in the sense that T (π |o) = T (π |o) Finally, we present the definition for execution conflict equivalence with respect to anobject o.

Definition 4.9. Let κ1 ⊢ π1 and κ2 ⊢ π2 be modular well-formed runs and T1 = T (π1|o) and T2 = T (π2|o) be their the traces of their respective projections on o. κ1 ⊢ π1 and κ2 ⊢ π2 are object ≃o conflict-equivalent for an object o, denoted π1 C π2, if: (i) κ1(o) = κ2(o), (ii) |T1| = |T2|, (iii) there exists a permutation φ : {1..|T1|} → {1..|T1|} such that: (a) for any i ∈ {1..|T1|} it holds that T1(i) = T2(φ(i)), and (b) for any i, j ∈ {1..|T1|}, if Conflict(a(T1(i)), a(T1(j))) then i < j ⇐⇒ φ(i) < φ(j).

5 CORRECTNESS CONDITIONS In this section we give a formal definition for two notions of the ECF property: final-state ECF and conflict ECF. We start by formally defining callbacks and callback-freedom in executions. A stack frame γ is a callback frame (to object o(γ )) in a stack Γ if there exist stack frames γ ′ and γ ′′ such that Γ = _γ ′′_γ ′_γ _ and o(γ ) = o(γ ′′), but o(γ ) , o(γ ′). A stack Γ contains a callback (to o), denoted by CBo(Γ), if it contains a callback frame. A state s contains a callback (to o), denoted by CBo(s), if its stack does, and an execution π contains a callback (to o), denoted by CBo(π), if it contains a state s such that CBo(s). A stack resp. state resp. execution is callback-free (for o), f f f denoted by CBo (Γ) resp. CBo (s) resp. CBo (π), if it does not contain a callback. We now define what it means for an execution to be effectively callback free, or ECF, with respect to a given object o. Note that ECF is a property of both an execution π and some object o. Specfically, we are interested in the case where π has a callback to o. Definition 5.1. A well-formed complete execution κ ⊢ π is equivalently effectively callback-free o ′ ′ for an object o, denoted by dECF fs, if there is a well-formed callback-free run κ ⊢ π , which is final-state equivalent for o to π:

o ′ ′ o ′ ′ f ′ κ ⊢ π  dECF fs ⇐⇒ κ , π . κ ⊢ π ≃ κ ⊢ π ∧ CBo (π ) ∃ FS ′ ′ o We say that the execution κ ⊢ π is a witness for π being a dECF fs execution. o Checking dECF fs is difficult in practice, and undecidable in general for models with aninfinite state. We describe a stronger definition of ECF, based on conflict-equivalence, called ECFc, which permits an efficient algorithm for checking it. Interestingly, even though executions in our model do not allow for concurrency, callbacks can be thought of as allowing to express a limited subset of concurrent executions. In fact, the ECF property in our model is analogous to serializability in models that permit concurrency. Using this analogy, invocations are analogous to transactions. We show what this means to reorder invocations in the sequential semantics of SMAC. 1 1 m n 1 ϵ ι1 ··· ι2 ··· ι2 ι1 ϵ ι3 ··· ϵ 1 n 1 1 m ϵ ι1 ··· ι1 ϵ ι3 ··· ϵ ι2 ··· ι2 ϵ

1 n 1 m 1 ϵ ι1 ··· ι1 ϵ ι2 ··· ι2 ϵ ι3 ··· ϵ

1 m 1 n 1 ϵ ι2 ··· ι2 ϵ ι1 ι1 ϵ ι3 ··· ϵ

Fig. 8. The callback reorder . The first graph represents the original execution, which contains a callback (in red). The three other graphs represent all possible callback free executions. Red marks the moved callback transitions. Wave edges indicate that a call was replaced with a havoc transition.

In general terms, ECFc requires to find a callback-free execution which is conflict-equivalent to the execution with the callbacks. Conflict-equivalence requires that the trace of the callback-free execution is a permutation of the trace of the original execution. It is thus useful to start with a characterization of the legal permutations of an execution. Firstly, the permutation may not break program order of contract code. That is, the permutation must retain the ordering of events whose transitions are part of the same invocation π, and their state have the same depth as Depth(π). Secondly, we want to allow permutations that remove callback invocations from their original call location, and sets them to execute in a quiescent state, and still receive a modular well-formed execution. When we permute a trace such that a callback invocation is removed from its original place, we replace the call transition leading to the callback with a havoc transition. An example can be seen in Figure8, showing all legal permutations of a trace that has a callback-free execution with havoc transitions. Remark 5.2. A havoc transition is not part of the permuted trace; it is merely used to justify the execution which is no longer well-formed as we defined earlier.

Using modular well-formed executions, we can formally define the ECFc property for executions, dECFc: Definition 5.3. A well-formed complete execution κ ⊢ π is conflict-equivalently effectively callback- o free for an object o, denoted by κ ⊢ π  dECF c, if there is a modular well-formed callback-free run κ ⊢ π ′ which is object-conflict-equivalent to π for o: o ′ o ′ f ′ κ ⊢ π  dECF c ⇐⇒ π . κ ⊢ π ≃ κ ⊢ π ∧ CBo (π ) . ∃ C It is easy to prove that conflict equivalence implies final-state equivalence (see, e.g., [Bernstein et al. 1987]). Thus, it can be concluded that ECFc implies ECFfs as, by using Proposition 4.8, we can use the same witness for π being dECFc to prove that π is also dECFfs. o o Theorem 5.4. Let π be a well-formed complete execution. If π  dECF c then π  dECF fs. o Proof. Since κ ⊢ π  dECF c, there is a callback-free modular well-formed complete execution ⊢ ′ ⊢ ≃o ⊢ ′ f ( ′) ′| κ π such that κ π C κ π . It is easy to see that since CBo π then π o is too a callback-free and modular well-formed run. From an immediate generalization of Proposition 4.8 to runs, we ′ ′ ′ ′ conclude that for κ ⊢ π |o there is a context κ and a well-formed run κ ⊢ πˆ such that κ (o) = κ(o), ′ andT (π |o) = T (πˆ |o). It should be noted that the equality of the trace projected on o implies callback- f freedom for o is retained: namely, CBo (πˆ). Conflict equivalence implies final-state equivalence ([Bernstein et al. 1987]), hence, src(π) = src(π ′) and trg(π) = trg(π ′). Also, because conflict ordering ′ ′ o in primitive commands of o is retained between π |o and πˆ |o, we conclude that π ≃FS πˆ, therefore src(π ′) = src(πˆ) and trg(π ′) = trg(πˆ). It can be concluded then that since (i) src(π) = src(πˆ) and ′ o ′ trg(π) = trg(πˆ), (ii) κ(o) = κ (o), and (iii) πˆ is well-formed, then: π ≃FS πˆ. making κ ⊢ πˆ a witness o proving π  dECF fs.  Finally, as we are also interested in ECF as a property of objects (sECF), we extend the definitions of ECFfs and ECFc to objects (sECFfs and sECFc) instead of executions (dECFfs and dECFc), which we refer to as static ECF.

Definition 5.5. An object o is sECFfs if for every complete execution κ ⊢ π it holds that o o κ ⊢ π  dECF fs. o is sECFc if for every complete execution κ ⊢ π it holds that κ ⊢ π  dECF c .

6 DECIDABILITY This section discusses the decidability of verifying ECF. Using Rice Theorem (see, e.g., Hopcroft et al. [2006]), it is easy to show that verifying sECF, namely, statically verifying whether all executions of an object are ECFfs or ECFc, is an undecidable problem. Interestingly, checking ECFfs for a single o execution (dECF fs) is also undecidable. o Theorem 6.1. Given an execution κ ⊢ π, checking if it is dECF fs is undecidable. Proof. We show a reduction from the halting problem. SMAC is Turing-complete, thus we encode the operation of a Turing machine M as a command c ∈ Cmd. In Figure9, we present the code of a contract A. The store of A has a single field X initialized as 0, and a single argument denoted arд. The field X is unchanged by M. We also write the code of a contract B. The method of A is separated to 3 branches. If X , 0, 1 then the method returns without any effect. If X = 1, then X is updated to 2 and the method returns. If X = 0, then X is updated to 1 and if the argument is equal 0, we execute the TM M and update X to 2 if and when M finished running. If the argument is not equal 0, we call contract B. If right after B’s execution X is not equal 2, thenX is updated to 3. The code of B is calling to A. Therefore, when A calls B, B always creates a callback to A. We consider the execution π starting from the initial state in which A’s X field is equal 0, with arд , 0. This execution calls the object B, which calls back to A, and in the callback the value of X is set to 2. o We show that π is dECF fs if and only if M() halts. For the ‘if’ direction, we note that if M() halts, then the execution of A(0) from the state where X = 0 leads to X being set to 2 right after M’s run finished, and that execution has no callbacks, as required. For the ‘only if’ direction, wenote that the only callback-free execution that starts from X = 0 and ends with X = 2 is the call A(0), which is the execution that executes M(), and it is a legal execution only if M() halts. The reason that this must be the only execution, is that for any choice of input argument arд , 0 and context κ that maps a different code for B, does not allow reaching the required final state X = 2 unless callbacks are used. If κ(B) still calls back to A then clearly the resulting execution is not an eligible ECF witness. If κ(B) does not call back to A, then X is updated to 3. Therefore, when X = 3, any subsequent call to A cannot modify X, and in particular X = 2 is not reachable. 

In contrast, checking ECFc for a single execution (dECFc) is obviously decidable, as we can enumerate all of the permutations of a particular input trace. Thus, we focus on verifying sECF, namely, statically verifying whether all executions of an object are ECFfs or ECFc, where the domains of the object variables are restricted to finite sets. Hence, such objects can be modeled with a pushdown-automaton (PDA). Such a PDA for an object o is able to simulate any modular well-formed execution κ ∈ π where the active object of all states in π is o. We denote this construction Ao. Its code is shown in the left side of Figure 10. It executes the code of o with a non-deterministically chosen argument, and replaces every call to an external Object B Object A enter int X A(0) M’s fields return enter (arg) if X == 0 then X := 1 if arg != 0 then B() if X != 2 then X := 3 M() X :=2 qX =2 0 = else A(a) X :=1 a rA run M() qX =0 a X ,2 X := 3 eAX =0 , B() 0 A(0) X :=2 X := 2 qX =3 else if X == 1 then eB ecb rB rA AX =1 X := 2 return

o Fig. 9. The codes of two objects A and B showing that dECF fs is undecidable, and a diagram showing the possible flows of the system. Nodes marked q are quiescent states, with the current value of A’s X variable in subscript. Nodes starting with eo indicate entry to an object o, and ro a return from an object o. The notation cb eo indicates the call is a callback. Entry nodes are marked with the value of X for better readability. Syntactic references to the code (assignments, calls, conditions) appear on the edges. Missing call edges from quiescent states indicate that the resulting quiescent state is the same, hence, qX =2 and qX =3 are sinks.

0 Ao Ao arg = *; arg = *; ... // Code of o ... // Code of o x := o’(y) --> E(); x := *; x := o’(y) --> x := *; ......

E = while (*) arg = *; o(arg);

0 Fig. 10. The construction of automatons Ao and Ao. The notation --> indicates that a command in the code of o is replaced with another. object with a sequence of arbitrary calls to o (the code in E), and a non-deterministic choice of the return value of the call. We begin with a rather simple lemma that shows ECFfs of objects is indeed decidable in this model. We assume that variables may take values coming from a finite domain. Lemma 6.2. Let o be an object, assuming a finite domain for variables. Then there is an algorithm that decides if o is sECFfs.

Proof. We consider the pushdown automaton Ao and an automaton that allows only callback- 0 free behaviors for o, Ao. Both are shown in Figure 10. Each execution of Ao consists of first choosing non-deterministically an argument arд with which the object o is called. The automaton simulates the steps of o with the only difference being in invocations of other objects, e.g. o′. This command is replaced with the code of the “environment” object E, that performs a sequence of calls to o with an arbitrary argument chosen in each iteration. The sequence length is arbitrary and may be also 0, i.e., no callbacks. After running the callbacks, the automaton non-deterministically chooses a return value, stored in the original variable intended to store the return value of o′, which in the figure is the variable x. The automaton that allows only callback-free behaviors for o is simpler: the only difference is 0 that it does not run the code of E. In fact, Ao is a finite state machine. We now utilize the result by [Bouajjani et al. 1997] for reachability of a regular set of config- urations of a pushdown automaton. Here, the set of configurations is State, and the subset of configurations which we are interested in is the one with with an empty stack,i.e. {()} × Σo where Σo is the set of o’s possible states, which is finite and thus regular. We consider an arbitrary pair of states σ1, σ2 ∈ Σo. We first check if there is an execution of Ao starting from σ1 and ending in σ2. This can be done by checking if σ1 is reachable from the initial state and as well as if σ2 is reachable from σ1. As the path that shows reachability in Ao may not be 0 callback-free, we check for reachability also in the finite state machine Ao, in the same manner. 0 Reachability in finite-state machines is known to be decidable. If there is no execution in Ao from σ1 to σ2, then the object o is not sECFfs. After checking for all pairs in Σo × Σo that for each pair of states (σ1, σ2) there is an execution of Ao starting in σ1 and ending in σ2 if and only if there is 0 such an execution in Ao, we verified that o is sECFfs. The set of all pairs of states is finite, thus it describes a decision procedure for verifying sECFfs for an object o. 

Showing the decidability of sECFc of objects is not that easy, because it requires reasoning on permutations of events, which is not a regular property, even in the case of finite-state machines. Our strategy for proving the decidability of sECFc will be as follows. As before, we consider executions of Ao, which identify with the set of possible projected executions on o. We will show that it is enough to check subexecutions of Ao which involve at most two elements of the stack. Namely, it is the same as checking the set of executions of Ao with a limit of two to the depth of the stack, where the initial state of the execution may include both the initial states Σo of an execution of Ao, and in addition any state s where a callback may be called. Explicitly, s is a state whose primitive ′ ′ command is a call. We describe such states using the set I0 = {s | x,o , e.C(top(s)) = x B o (e)}. ∃ It is regular as we only consider the top element of the stack. Finding for the set of states I0 its subset of reachable states in Ao can therefore be done using [Bouajjani et al. 1997]. 2 We denote by Ao the automaton that is received by limiting the stack depth of Ao to two, and 2 o having initial states I0 ∪ Σo. For Ao, deciding if all its executions are dECF c is decidable. We do so 2 by constructing a monitor that receives as input execution traces of Ao and outputs an error if the o executions are not dECF c. Then we will show that M is a finite state machine and thus checking reachability of its error states is decidable. Such a construction is possible because even though conflict-equivalence demands finding a permutation of a trace, which is not a regular property,the actual choice of permutations that have to be checked is much more limited. 2 Lemma 6.3. Let Π denote the set of all executions of Ao. There is an automaton M that for each o π ∈ Π, ends in an accepting state if π  dECF c, and in a rejecting state otherwise.

Proof. We write the code of the automaton M in Figure 11. The automaton loops on each event in the trace of the execution. The automaton states consist of a depth variable d, and two pairs of read and write sets: prefix and delayedCbs. The sets R and W are updated in each command that reads from or writes to the object store. They are reset when a callback starts or ends. The prefix pair retains the accumulated reads and writes in the invocations at depth 1, i.e. the first invocation of o and which we refer to sometimes as the main invocation. The delayedCbs pair retains the accumulated reads and writes by callbacks that we choose to execute after the main invocation ends. M(π ) = d = 0, prefix = (∅, ∅), delayedCbs = (∅, ∅) for (e ∈ T (π )) if (c(e) = x B F ) R := R∪{F } if (c(e) = F B x) W := W∪{F } if (c(e) = enter && d=0) // Execution starts R, W := (∅, ∅) d := d+1 if (c(e) = return && d=1) // Execution ends assert((R,W) commutes with delayedCbs) R, W := (∅, ∅) d := d-1 return if (c(e) = enter && d=1) // Callback starts assert((R,W) commutes with delayedCbs) prefix := (R(prefix) ∪ R, W(prefix) ∪ W) R, W := (∅, ∅) d := d+1 if (c(e) = return && d=2) // Callback ends if (!((R,W) commutes with prefix) || !((R,W) commutes with delayedCbs)) delayedCbs := (R(delayedCbs) ∪ R, W(delayedCbs) ∪ W) R, W := (∅, ∅) d := d-1

2 o Fig. 11. The code of M which accepts an execution π of Ao and verifies if it is dECF c

Intuitively, the monitor checks each time a pair of (R,W) is finalized and before it is reset, ifit satisfies conditions that will allow to find a conflict-equivalent execution. For a callback execution, we check if the pair commutes with the prefix, i.e. all portions of the main invocation already executed. If it does not commute with the prefix, we mark it as a delayed callback, and update the delayedCbs read and write sets. As we do not know whether delayed callbacks actually commute with the rest of the invocation, and with future callbacks that may be executed before the main invocation, we retain the conflict information in delayedCbs to be checked later against any finalized (R,W) sets that is belonging either to the main invocation, or to a callback that is chosen to be executed before the main invocation. Therefore, even in the case when a callback commutes with the prefix, but in which it does not commute with the delayed callbacks (which are ‘jumping over’ the callback under consideration in order of execution), we have to try to execute it as a o delayed callback as well. Otherwise, the execution is surely not dECF c, and we move to an error state. For a portion of the main invocation (the first or last one, or between callbacks), we check if it does not conflict with any of the relevant delayed callbacks. The delayedCbs pair is always updated correctly with the currently delayed callbacks’ read and write locations. It can be seen from the construction that if M accepts, then we can build from M’s execution a o witness for π being dECF c by ordering all non-delayed callbacks before the main invocation and the delayed callbacks after the main invocation, both of those in the order in which they appear in the original execution. E.g., if callbacks i1 and i2 are both delayed callbacks, then if i1 is executed before i2 in π then the ordering between them in the witness is not changed. The same argument applies for non-delayed callbacks. o o In addition, if o is dECF c then M must accept. This is because any witness for π being dECF c is conflict-equivalent to the witness implicitly produced by M. The reason for that is that in the witness, we can also identify a set of callbacks executed before the main invocation and a set of callbacks executed after it. The internal ordering of callbacks that are executed before the main invocation does not matter as long as it does not reorder conflicts, and thus may in fact be the same as in the original execution, ditto for the other set of callbacks.  We note that M has a finite state: d in {0, 1, 2}, and prefix and delayedCbs in 2F × 2F where F is the set of o’s fields. Therefore, M is a finite state machine, and thus reachability is decidable. In particular, we can check if the error states are reachable. However, M is a machine that works on 2 any execution of any object. It is not difficult, though, to build M as a monitor of Ao. We denote 2 this construction M 2 . The result is still a finite state machine with decidable reachability, since A , Ao o which has a bounded stack depth of 2, is also a finite state machine. 2 o Corollary 6.4. It is decidable to check if all executions of Ao are dECF c 2 o We now show that the previous corollary implies that if all executions of Ao are dECF c, then then so are all executions of Ao. In particular, it shows that o is sECFc. Importantly, the converse is 2 o also true: if an object o is sECFc, then all executions of Ao are dECF c. This is trivial to show: for 2 o ′ an execution π of Ao such that π¬dECF c it is easy to find a complete execution π in Ao of the ′ ′ o form π = π0ππˆ 0 which is also not dECF c. Specifically, π0 will be a subexecution that reaches the initial state of π, πˆ will be identical to π, only changing the stacks in π’s states to account for π0’s ′ ′ transitions, and π0 will complete the execution. Any permutation of T (π ) will induce a conflict equivalence breaking permutation on πˆ, whose conflicts are the same as those of π, therefore π ′ is o not dECF c. 2 o Lemma 6.5. An object o is sECFc if all executions of Ao are dECF c. ′ o Proof. We show that for every execution π of Ao there is a witness π for it being dECF c. The witness is built recursively. We initialize π ′ = π. We denote D = maxDepth(π). We start with the longest subexecution in π0 ⊑ π which has maxDepth(π0) = D and minDepth(π0) = D − 1. By 2 o ignoring the first D − 2 stack frames, π0 can be seen as an execution of Ao, thus it is dECF c. Hence, 2 by taking the witness in Ao and returning the first D − 2 stack frames, we have a subexecution ′ ≃o ( ′) ( ′) − ′ π0 C π0 which is callback-free: minDepth π0 = maxDepth π0 = D 1. We update π by replacing ′ the transitions of π0 with π0. The process continues by taking in each step the longest and deepest subexecution which has a callback and replacing it with a callback-free subexecution which is conflict-equivalent to it. In each step, the resulting π ′ is conflict-equivalent to π. The premise of the lemma ensures that this process will not stop until π ′ is callback-free.  From Corollary 6.4 and Lemma 6.5 we immediately get the following result: Theorem 6.6. Let o be an object, assuming a finite domain for variables. Then there is an algorithm that decides if o is sECFc.

7 OBJECT-LEVEL ANALYSIS While the ECF property is capable of detecting unwanted executions which do not satisfy it, it can be further used for modular analysis of objects. We will show that in environments in which objects are encapsulated, we can consider ECF for executions of a single object only, to help simplify object-level analysis. We define the notion ofa most general client (MGC) in our model. The most general client for an object o, MGCo, is an external program that works on a system that includes a single object in the store. The store σ of MGCo contains a single object NoCB(o), which is built based on the original object o. Every invocation of an object of the form x B o′(e) in o is replaced with a non- deterministic choice of the value of x as returned by the call, in correspondence with the definition of havoc transitions in Section5. Furthermore, MGCo is allowed to repeatedly call NoCB(o) with any parameter and in any order. As such, the semantics of MGCo soundly approximate all executions of the object o (see, e.g., Gotsman and Yang[2011]), while every execution in MGCo is in fact a projected, callback-free execution of o. We show that, if the object o is ECF in the general model, then any object-level assertion can be soundly verified on MGCo. This is because, all reachable states of an object o in any arbitrary code context κ that does not change o’s code, are reachable in the system containing only NoCB(o).

Theorem 7.1. Let R be the set of all states of the object o in a quiescent state, and let R0 be the set of all states of the object o in a run of MGCo. If o is sECFfs then R0 ⊃ R.

Clearly, the theorem holds if the object is shown to be sECFc, since this implies it is also sECFfs (see Theorem 5.4). This analysis is not overly imprecise, since in real environments, such as Ethereum, we could simulate such behaviors. This is particularly correct since in Ethereum the store of the objects is updateable, and new objects may be added to the system. Importantly, the analysis simply assumes ECF, and does not require to prove it: An alternative formulation of Theorem 7.1 is assuming that the runtime system enforces dECF on all executions. In that case, the analysis is still sound. It is not unreasonable to assume such a dynamic analysis of dECF, because we found out an efficient method to verify it, presented in Section8. We illustrate Theorem 7.1 using the example shown in Figure1. We implemented Dao as a class in Dafny [Leino 2010] with two methods: deposit and withdrawAll, whose pre- and post- conditions capture the object invariant which should be valid after every execution of the Dao object. Primarily, we wish to ensure that the data elements in the credit map are not negative, and that the sum of all these elements is equal to the balance of the Dao. We model the pay method without the recursive call to withdrawAll, but annotate it as possibly modifying (any field of) the Dao object. This annotation generalizes the possible behaviors of the Dao object without the ECF property. With such weak assumptions, and perhaps unsurprisingly, Dafny fails to verify the postconditions for both the original and the fixed versions of the Dao object. In contrast, when we assume that the ECF property holds, technically by adding a postcondition to pay which ensures that the previously read fields of the Dao object, i.e., balance and credit[o], are not modified, Dafny is able to establish the post condition. Theorem 7.1 implies the fixed Dao contract respects the given specification when executed using the original runtime system and the original DAO object respects the specification if it is executed on a runtime system which enforces ECF.

8 DYNAMIC VERIFICATION

We describe a sound procedure for verifying the dECFc property dynamically. More precisely, for each execution, it checks for every object that participates in the execution, if the subsequence of the transitions that pertain only to that object (the projected execution) is ECFc. We assume the existence of an interpreter or virtual machine implementing the semantics defined in Section3. Below is a description of the data structures used by the algorithm, as well as the instrumentation of the object code to maintain these data structures. We then present a higher-level description of the algorithm, followed with pseudo-code and a complexity analysis. We use the example presented in the overview section in Figure1 to explain the procedure. The general structure of the procedure is that the instrumentation step starts every time we exit a quiescent state, and ends when we reach the next quiescent state. Once instrumentation has completed, the algorithm runs on the instrumented structures and returns whether all projected executions derived from the execution are ECF. The procedure repeats each time we enter an active state. 8.1 Data Structures A segment is a data structure that captures metadata about a portion of the execution’s states. This portion consists of a sequence of adjacent transitions, whose top stack frames have the same active object. That is, an invocation of a different object marks the beginning of a new segment, as well as returning from an invocation to a caller invocation which is executed in the context of a different object. However, a call from one object to itself does not break the current segment(This is motivated by the definition of callbacks in Section5). In simpler terms, a new segment is defined each time the active object changes, either when we push a stack frame with a different object, or pop a stack frame such that the new top frame has a different active object. We show how segments are determined in the instrumentation in Figure 12, using hooks on calls and returns. Example 8.1. In the example DAO contract in Section2, an attack execution consists of 6 segments: (1) the first invocation of withdrawAll, lines 1-3; (2) an invocation of pay, lines 3-5; (3) the second invocation of withdrawAll, lines 1-3; (4) a full invocation of pay, lines 3-4,7; (5) the second invocation of withdrawAll, line 5; (6) the first invocation of withdrawAll, line 5; Definition 8.2 (Segments). A segment t is representative of a maximal sequence of adjacent transitions pertaining to the same object. A segment t = (R,W , D, Idx) contains information about fields accessed in the segment, denoted R(t) and W (t) for the read- and write- sets, respectively. In addition, a segment contains information about the depth of the invocation (denoted D(t)), which is equal to the depth of the transitions’ states. Last, the index in the execution (denoted Idx(t)), is strictly increasing according to order of creation of the segments. The primary metadata saved in each segment is the read and write sets of the fields of the object that were accessed by commands executed in the transitions that pertain to the segment. Other metadata includes the depth of the invocations in the stack, and an index to maintain the order of the segments in the execution. Example 8.3. We write down the segments that pertain to the DAO object in the overview example of the attack execution, in the same order as they appear in the execution:

t1 = ({credit[Attacker], balance}, {balance}, 0, 1) t2 = ({credit[Attacker], balance}, {balance}, 1, 2) t3 = ({}, {credit[Attacker]}, 1, 3) t4 = ({}, {credit[Attacker]}, 0, 4) An execution can be represented as a linear sequence of segments. Furthermore, from these segments we can determine the invocations that the execution contains. Remark 8.4. Segments can be used as an alternative representation of executions and invocations, that generalize data saved by a sequence of transitions. In this section only, we redefine the notions of executions and invocations to refer to segments instead of transitions. Definition 8.5 (Executions, Invocations, and Callbacks). An execution can be represented using a sequence of its instrumented segments π = (t1,..., tn). We can access the j’th segment of the execution using π(j) = tj . We trivially have that Idx(tj ) = j. An invocation is a sequence of segments ( I I ) I = t1,..., tk such that there is a number d for which all of the following holds: (1) t ∈ I.D(t) = d (all segments of the invocation are in the same depth). ∀ I (2) d > D(π(Idx(t1) − 1)) (the first segment before the first segment in the invocation haslower depth, proving it is indeed the beginning of an invocation). ( ( ( I ) )) (3) d > D π Idx tk + 1 (the first segment after the last segment in the invocations has lower depth, proving it is indeed the end of an invocation). ( I ) ( I ) ⇒ ( ( )) ≥ (4) j.Idx t1 < j < Idx tk = D π j d (the invocation does not end before the last segment,∀ that is all segments of depth d in the given range belong to the same invocation). As all segments included in the invocation has the same depth d, we denote the depth of an invocation by D(I) = d. We say that an invocation I is a callback in another invocation I ′ (denoted I ⊑ I ′) if Idx(I(1)) > Idx(I ′(1)) ∧ Idx(I(1)) < Idx(I ′(|I ′|)). Remark 8.6. Unlike the definition of invocations in Section3, here invocations capture only the transitions in the same depth as the depth of its first transition, and not transitions in higher depth. This allows to define D(I) for an invocation I. Example 8.7. In the attack execution presented in Section2, the first invocation of withdrawAll is Iwd1 = (t1, t4), and the second invocation is Iwd2 = (t2, t3). Iwd2 is a callback of Iwd1 : Iwd2 ⊑ Iwd1 . We associate with each segment in depth > 1 a prefix-set and suffix-set of all segments in the caller that precede, or respectively, proceed it: Definition 8.8 (Prefix and Suffix segments). Let a set of segments representing an invocation ( i ) ( ) ( ) ( ) ∈ { ( ( )) ( (| |))} I = tcaller , and a single segment tcb with D tcb > D I and Idx tcb Idx I 1 ,..., Idx I I . We define for tcb its prefix and suffix sets relatively to acaller I by partitioning the segment in I to segments whose index in the execution is smaller than the index of the callback segment tcb (prefix), and segments whose index in the execution is larger than it(suffix):

prefix(I, tcb) = {tcaller ∈ I | Idx(tcaller ) < Idx(tcb)} suffix(I, tcb) = {tcaller ∈ I | Idx(tcaller ) > Idx(tcb)}

Example 8.9. The prefix and suffix segments of t2 and t3 with respect to Iwd1 are:

prefix(Iwd1 , t2) = prefix(Iwd1 , t3) = {t1}

suffix(Iwd1 , t2) = suffix(Iwd1 , t3) = {t4} The instrumentation process creates the segments and the invocations. We show pseudo-code of the instrumentation procedure in Figure 12. The basic check on segments is the commutativity check. We define segment commutativity using read and write sets. We will show that we actually check commutativity of a segment with either a prefix or suffix segment. As the prefix/suffix segments are sets of segments, thereadand write sets of prefix/suffix segments are a union of the respective read and write sets ofallthe segments contained in the prefix or suffix segment.

Definition 8.10 (Commutative Segments). Segments t1 and t2 commute, denoted by t1 ⇄ t2, if:

def t1 ⇄ t2 = R(t1) ∩ W (t2) = ∅ ∧ R(t2) ∩ W (t1) = ∅ ∧ W (t1) ∩ W (t2) = ∅

If segments t1 and t2 do not commute, we denote this by t1 ⇄̸ t2.

Example 8.11. In the attack execution presented in Section2, indeed we have that t2 ⇄̸ t1, as R(t1) ∩W (t2) = {balance}. Similarly, t3 ⇄̸ t1 because of credit[o], as R(t1) ∩W (t3) = {credit[o]}, and therefore also t2 ⇄̸ t4. However, t3 does commute with t4: t3 ⇄ t4.

8.2 Algorithm We start with a high-level description of the algorithm. The algorithm is called every time the system reaches a quiescent state, working on the last complete execution. The algorithm generates a relation of invocations that defines constraints on the ordering of invocations in different stack depths, similar to a ‘happens-before’ [Lamport 1978] relation. We name this relation the invocation order constraint (IOC) graph. For example, if a segment t of a callback invocation Icb is not commuting with its prefix with respect to one of its calling invocations tcaller (i.e., t ⇄̸ prefix(Icaller, t)), then we Segment { Obj, Caller, R, W, D, I } Invocation { Caller, Obj }

Init (): execution := () curSegment := ⊥ invocations := Map Segment>

UponInvocation(object): if fromQuiescent // Procedure starts Init ()

if object != curSegment.Obj caller := fromQuiescent ? TopInvocation : curSegment.Caller inv := Invocation(caller, object) AddSegment(object, inv, curSegment.D+1, curSegment.I+1)

UponReturn(object): caller := toQuiescent ? TopInvocation : curSegment.Caller.Caller if caller.Obj != object AddSegment(object, caller, curSegment.D-1, curSegment.I+1)

if caller == TopInvocation // End of instrumentation step CheckECFForAllObjects() // Run the algorithm, and finish procedure

AddSegment(object, caller, D, I): segment := Segment(object, caller, {}, {}, D, I) Append(execution, segment) Append(invocations[caller], segment) curSegment := segment

UponObjectVarRead(object, F): curSegment.R[F] := 1

UponObjectVarWrite(object, F): curSegment.W[F] := 1

Fig. 12. Instrumentation procedures, implemented as hooks called upon call commands, return commands, and object variable read/write access command. Generates the execution, which is a list of segments, and invocations, a map of invocation identifiers to an invocation object keeping the caller of an invocation and the list of segments that are part of the invocation in the same depth. The top-level invocation is identified as TopInvocation.

add the constraint that the invocation of the caller has to occur before the callback: Icaller ≺Inv Icb. The IOC relation of invocations is thus defined as: ′ def ′ ′ I ≺Inv I = (I ⊑ I ∧ t ∈ I .t ⇄̸ prefix(I, t)) ∨(I ⊑ I ′ ∧∃ t ∈ I.t ⇄̸ suffix(I ′, t)) ∃ Example 8.12. The IOC relation of the attack execution in Section2 can be easily calculated with the previous metadata given in examples 8.9 and 8.11. We have that Iwd1 ≺Inv Iwd2 as Iwd2 ⊑ Iwd1 and for t2 ∈ Iwd2 , t2 ⇄̸ prefix(Iwd1 , t2). Similarly, Iwd2 ≺Inv Iwd1 as for t2 ∈ Iwd2 , t2 ⇄̸ suffix(Iwd1 , t2). After the IOC relation is defined, the algorithm considers the graph induced by this relation, and checks it has no cycles. A cycle in the graph could appear if, for example, there is a callback invocation and some caller invocation that contains it, for which there is both (1) a segment that does not commute with its prefix with respect to the caller; and (2) a segment that does notcommute with its suffix with respect to the caller. As each vertex in this graph represents an invocation, the topological sorting returns an ordering of the invocations, which is ECFc. We are merely interested if there is such a topological sorting, that is, if the IOC relation does not contain a cycle. Theorem 8.13. Let π be an execution and let Inv be a map of the instrumented invocations to their segments. We denote by ≺Inv the IOC on Inv. If ≺Inv has no cycle, then π is ECFc. t Proof. We assume ≺Inv has no cycle. We take a total order ≺Inv of Inv induced by the transitive t ′ closure on ≺Inv. From ≺Inv we build a run π such that every invocation in Inv starts in a quiescent t ′ state in the order determined by ≺Inv. π is conflict-equivalent to π. To show this, we consider two transitions τ1 and τ2 which conflict in π. If τ1 and τ2 are both captured in the same segment during instrumentation, then their ordering is kept in π ′ which only reorders invocations. In particular, the program order of invocations is kept. The same argument applies when τ1 and τ2 are not captured by the same segment, but their respective segments are both part of the same invocation. In the general case, τ1 and τ2 each belong to different segments, pertaining to different invocations. In ′ t that case, their ordering in π is kept as ≺Inv respects that conflict.  Example 8.14. In continuation to our running example, it is immediate that the IOC relation of the attack execution on the DAO object has a cycle: Iwd1 ≺Inv Iwd2 ≺Inv Iwd1 . Therefore, the algorithm cannot determine the attack execution is ECFc. But indeed, the attack execution is not ECF, thus it cannot be ECFc. We already saw in Section7 that due to state encapsulation, ECF is a modular property. Therefore, the procedure may either check ECF for the entire execution, by searching for a cycle in the full IOC relation, or to check ECF for one object at a time. A modular ECF check can be done by projecting the relation only on invocations of the object under examination. To align with the actual implementation of the algorithm, we chose to present it in its modular version here as well. We give the complete pseudo-code of the algorithm in Figure 13. It begins with an additional step of preprocessing which is calculating the commutativity matrix of all segments against all prefix and suffix segments of all their enclosing invocations (invocations that directly or indirectly callthe invocation in which the segment is included). The commutativity matrix assists in calculating the IOC relation. We then iterate over all objects encountered in the execution, project the IOC relation on a single object in each iteration, and check if it has a cycle. If the check returns that it is a DAG, then we verified the projected execution is ECF. Otherwise, the cycle describes the invocations which cannot be moved, and helps identify the callbacks that cause the violation of ECF.

8.3 Complexity 8.3.1 Time. The instrumentation step adds a constant factor of work to the runtime. To analyze the algorithm, we begin by looking at the preprocessing steps first. Let n denote the number of invocations and m the number of segments (n < m). In addition, let k denote the maximal number of object variables accessed in an object participating in the execution (k < m). The CalculateCommutativityMatrix procedure loops on all invocations and all segments. For each pair of an invocation and a segment, the encloses predicate can be implemented to take constant time. The calculation of the prefix set and suffix set is taking time linear in the number ofsegmentsin an invocation, bounded bym. The time to calculate the read and write sets of the prefix and the suffix set is linear in k. Commutativity check, which involves checking set intersection, where our sets are implemented as associative arrays, is linear in k. Thus the time of CalculateCommutativityMatrix is O(nm(m + k)) = O(nm2). For CalculateIOCRelation, we have a loop over pairs of invocations, and another pair of non-nested loops over segments in an invocation, giving O(mn2). Projecting the IOC relation is linear in its size which is O(n2). The isDAG check is linear in the size of the CheckECFForAllObjects(): commute_matrix := CalculateCommutativityMatrix() hbRelation := CalculateIOCRelation(commute_matrix) for each unique object in execution: if not CheckECF(object): Print "Object " object " is not ECF"

CheckECF(object): // It is guaranteed that IOC applies only to invocations of the same object hbRelationO := project hbRelation on invocations of object only return isDAG(hbRelation)

CalculateCommutativityMatrix(): matrix := new Map Bool, Bool> for each inv in invocations, segment in execution if encloses(inv, segment) prefix := (s for s in inv where s.I < segment.I) suffix := (s for s in inv where s.I > segment.I) prefixRS, prefixWS := Union(s.R for s in prefix), Union(s.W for s in prefix) suffixRS, suffixWS := Union(s.R for s in suffix), Union(s.W for s in suffix) prefixCommute := isCommutative(prefixRS, prefixWS, segment.R, segment.W) suffixCommute := isCommutative(suffixRS, suffixWS, segment.R, segment.W)

if prefixCommute == False && suffixCommute == False Abort("Not ECF") matrix[inv, segment] := prefixCommute, suffixCommute

return matrix encloses(inv, segment): return inv.Obj = segment.Obj && segment.I between first segment and last segment in inv

CalculateIOCRelation(commute_matrix): rel := new Map Bool> for each inv1, inv2 in invocations if encloses(inv1, first segment in inv2) for each segment in inv2 if commute_matrix[inv1, segment] == False, True rel[inv1, inv2] := True

if encloses(inv2, first segment in inv1) for each segment in inv1 if commute_matrix[inv2, segment] == True, False rel[inv1, inv2] := True

Fig. 13. Algorithm for verifying ECF of an execution. The code of isDAG and isCommutative is not given. The definition of isCommutative is given according to Definition 8.10.

projected relation, which is bounded by O(n2). (The graph it represents has O(n) vertices and O(n2) edges, and checking for a graph to be a DAG is O(|V | + |E|)). In total, we have O(nm2).

8.3.2 Space. The instrumentation adds O(m) space for keeping the segments, and O(nm) for keeping the invocations. The commutativity matrix takes O(nm) space, and the IOC relation takes O(n2) space. Therefore, the space complexity of the algorithm is O(nm). 9 EVALUATION We developed a prototype implementation for a dynamic monitor verifying ECF for Ethereum.6 For each execution, it checks if any of the participating contracts has a non-ECF (projected) execution, and outputs all detections of non-ECF executions.7 We ran our experiments by importing the entire blockchain from its inception on July 30, 2015 until March 30, 2017. 8 The host we used is a 64-bit Ubuntu 16.04 with two 2.2 GHz Intel Xeon E5-2699 processors (22 cores each with 2 threads per core) and 256 GB of RAM. Both the instrumentation and the algorithm were integrated directly into the Ethereum Virtual Machine (EVM) module using hooks, as described in Section8. Our monitor operated in “’detect-mode” to avoid affecting the results, and for statistics gathering only. However, it is trivial to change it to “’prevent-mode”, that actively invalidates and reverts complete executions which are not ECF. Had all the Ethereum clients used such a monitor by design, the DAO incident would have been avoided, along with the controversial hard fork. As our experiments prove, the false-positive rate of the monitor is minuscule: only 10 executions out of about 100 million were legitimately non-ECF. There is also no concern of performance impact, as the measured overhead of running the monitor was less than 3.5%. Furthermore, the benchmarks of the monitor were performed in an ideal environment that actually makes the overhead larger than it is in a normal environment. The reason behind it is that normal environments have additional overheads such as networking and disk accesses, which we disabled in order to scale our experiments. Experiments. In Figure 14, we show a short list of experiments conducted. We also included the number of contracts created as an additional metric of the blockchain. The primary experiment was checking for ECF in all executions since the creation of blockchain until March 30, 2017. Of note is that less than 0.01% of the executions were non-ECF. In the second experiment, we processed all executions starting from March 30, 2017 until June 23, 2017 9. It is interesting to compare the results of the first experiment, conducted on a snapshot of the Ethereum blockchain taken in Mar. 30th, 2017, which we used for benchmarks, to the second experiment, in which we let our modified client to process all newer executions, until June 23rd, 2017. The number of non-ECF contracts decreased in both absolute quantity and in percentage of total executions. The newer executions expose the maturity of the network, expressed in both the number of total contracts created (almost 150% more contracts created in less than 3 months than in the entire existence of the blockchain, from August 2015 till the snapshot date), and the number of executions.10 Moreover, the number of executions with callbacks increased significantly, indicating more complex contracts. In the first experiment there were 128, 670 executions containing callbacks, and in the second experiment there were 155, 668 executions with callbacks. This amounts to a 641% increase in the number of callbacks in the later period compared with the earlier period. While the percentage of executions with callbacks is still only 1% of all executions, the absolute number of executions with callbacks is large enough to indicate that callbacks are inevitable, either because they are useful, or necessary. This means that contracts show an increasing use of callbacks, and thus more complex code, that may be prone to bugs resulting from unintended interaction between contracts. In both experiments, the overall percentage of non-ECF executions out of the executions with callbacks, was 1.17%, and less than 0.01% out of all executions.

6The source code is available at https://github.com/shellygr/ECFChecker. 7The monitor was implemented on top of the Go [Pike 2012] client for Ethereum, called geth [Ethereum Foundation 2017a], version 1.5.9. 8Without delving into the specifics of the blockchain paradigm, executions are organized in a structure called blocks. Our primary experiment was to import the first 3,444,354 blocks of the main Ethereum blockchain. 9The second experiment processed all blocks from block no. 3,444,355 to block no. 3,918,380. 10Assuming a new block is generated at an almost constant rate, there were 32 executions per block on average in the second experiment, compared with 23 executions in the first. Blockchain Date Contracts Executions Callbacks Non-ECF (%) Ethereum 30.VII.2015-30.III.2017 138,457 81,097,421 128,670 3,315 (0.004%) Ethereum 30.III.2017-23.VI.2017 203,859 15,311,650 155,662 6 (<0.001%) Eth. Classic 30.VII.2015-29.VI.2017 91,191 32,494,464 81,731 2,288 (0.007%)

Fig. 14. Experimental results. We use dates to mark the portion of the blockchain checked in the experiment. The Contracts column shows how many contracts were created (but not necessarily executed) in the relevant time period. The Executions column records the number of method invocations and the Callbacks column shows how many of these invocations were callbacks. Non-ECF column counts how many non-ECF executions were detected, and their percentage out of the total number of executions.

Object C Object Sender Method call(data, sender) if (Sender != nil) throw Sender = sender; ret = this.do(data); Sender = nil

Method do(data) ... // read Sender

Fig. 15. Pattern used by contracts C6, C8 and C9. Sender is initialized to nil. call is a method that throws when Sender is not nil, and otherwise sets it, calls method do, and nullifies Sender afterwards.

Discussion of non-ECF examples. We present a list of all contracts that demonstrated non-ECF executions in Figure 16. Contracts C2, C4 are related to the DAO. C2 is the original DAO [Buterin 2016]. C4 is known as ‘The Dark DAO’ [Pfeffer 2016], an object containing a copy of the DAO’s code, as created by the attack (The mechanism of the DAO was such that, every withdrawal of funds, manifested in the form of a new object whose code is a copy, or ‘split’, of the DAO code). Contract C1 is an unrelated contract which suffered a vulnerability very similar to the DAO’s. The vulnerability, also stemming from non-ECF behavior, was discovered during a security audit and disclosed shortly before the attack on the DAO [Ethereum Reddit 2016; Vessenes 2016]. Contract C5 is an exercise published on the blockchain to demonstrate the DAO attack [B9Lab 2017], and indeed a non-ECF execution was detected. In some contracts, it is difficult to pinpoint the exact cause of the existence of non-ECF executions, as the only available code is EVM bytecode, which is not trivial to analyze and reverse. We tried to connect these incognito contracts with their creators or users. With this approach, we found evidence that C3 is also related to the DAO [p-s-dev 2016]. The contract at C7 [Etherscan 2017] was traced back to Validity Labs [Val 2017]. We contacted the authors and they provided us with the Solidity source-code of the contract [Validity Labs 2017]. It was deliberately designed to have a DAO-style callback exploit, and was used in their training workshops to demonstrate its dangers. The same high-level Solidity code of contracts C6, C8, and C9, were provided to us by their creators at Ambisafe [Ambisafe 2017]. The pattern used by these contracts gives rise to behaviors that are purposefully non-ECF. We show a snippet illustrating the pattern in Figure 15. This pattern is inherently non-ECF.11 The method do assumes the value of Sender is not nil, but this only

11In the formal definition, it actually is ECF, because a call of a contract to itself is not a callback. The contracts under examination were discovered due to a deviation of our monitor’s implementation from the full definition of ECF. However, this example can be fitted into a slightly modified pattern which is not-ECF even according to the full definition, byadding an intermediary contract between call and do. Name Contract address Execs. Execs. w. cbs. Non-ECF Stack depth Ethereum Network (ETH) C1 0xd654bdd32fc99471455e... 924 143 10 3 C2 0xbb9bc244d798123fde78... 274,820 103,064 3,296 2-146 C3 0x34a5451ef61a567ee088... 91 8 1 46 C4 0x304a554a310c7e546dfe... 13,223 2,812 1 3 C5 0x59752433dbe28f5aa59b... 15 6 1 3 C6 0x97361ea911d6348cf2af... 44 42 6 2 C7 0xbf78025535c98f4c605f... 25 22 3 3-9 C8 0x232f3a7723137ced12bc... 144 142 1 2 C9 0x7c525c4e3b273a3afc4b... 35 33 2 2 Ethereum Classic Network (ETC) C1 0xd654bdd32fc99471455e... 850 143 10 3 C2 0xbb9bc244d798123fde78... 195,428 86,573 805 2-146 C3 0x34a5451ef61a567ee088... 18 9 1 46 C4 0x304a554a310c7e546dfe... 14,150 3,064 1 3 C10 0xf4c64518ea10f995918a... 428 177 11 42-122 C11 0xb136707642a4ea12fb4b... 2,582 305 201 17-20 C12 0x0e0da70933f4c7849fc0... 5,330 3,992 1,259 12-57

Fig. 16. A sample of interesting Non-ECF contracts in Ethereum. Contracts are given a name C1,..., C12, and are ordered chronologically, by the date of the first non-ECF execution. The Executions and Executions with callbacks columns show statistics on usage style. The Non-ECF column shows how many executions were detected as non-ECF. Stack depth column indicates the range of the depths of the non-ECF subexecutions.

Time Memory (max) Memory (end) Monitor off 16h 17m 5.5GB 803MB Monitor on 16h 50m (3.38% overhead) 5.5GB (0%) 940MB (17% overhead)

Fig. 17. Performance statistics. Benchmark experiment was importing the Ethereum main network blockchain, from its creation in July 30, 2015 until March 30, 2017. Compares the import with monitor on or off. occurs in the context of an invocation of call. The purpose behind this behavior, is to have Sender act as a , protecting against unexpected callbacks. Such a design may be avoided in presence of a monitor that allows only ECF executions. The bottom part of the table in Figure 16 shows non-ECF contracts found in Ethereum Classic [2017]. Ethereum Classic (or ETC) is the continuation of the original Ethereum blockchain following the controversy of the hard-fork due to the DAO bug. Until July 20, 2016, both blockchains, Ethereum and Ethereum Classic, contain the same executions, and thus the same non-ECF executions. Our result and investigation show that all non-ECF executions discovered in the Ethereum Classic network are of copies of the DAO [Bok Consulting 2016a]. Generally, it is important to stress that: (1) there may be other non-ECF contracts, as crafting and deploying contracts that exploit non-ECF entails investment of real money, thus requires a strong incentive to do so; (2) attacking is harder as Ethereum employs (not bullet-proof) heuristics to limit callbacks; (3) a better playground may be the Ethereum TestNet on which we did not run the experiment, but may provide insight as a future work. The actual overhead measured by enabling the ECF monitor is given in Figure 17. We used the first experiment, where the blocks were imported, as a benchmark. Normally, there is an additional overhead of network download times, which can vary significantly. The measured overhead is about 3.5%, when calculating the difference in time of importing the blockchain with the monitor off, and importing it with the monitor on. We believe the actual overhead is even smaller inmost realistic scenarios. First, most clients import the blockchain using the network, which may cause unexpected latencies, unrelated to the monitor. Additionally, the process was pointed to a directory created on a 200 GB RAM disk to improve the scalability of the experiment.12 Most clients use a physical disk and not a RAM disk. Even if the physical disk is an SSD drive, the experiment slows down significantly, and takes about 20h (18% more than with a RAMdisk). The additional memory footprint measured in the end of the import is about 140MB, or 17%. It should be noted, that as the implementation is written in Go, which includes automatic garbage collection, the memory consumption varies between tests. The relative difference with the monitor on or off was consistent across repeated tests. The maximal memory used by the process is 5.5GB and is not related to the monitor. High memory consumption occurred during the processing of one of the DoS attacks on the blockchain.

10 RELATED WORK 10.1 Modular Reasoning Modular reasoning is a topic which has been studied extensively with the seminal works of Hoare [1972] and Dijkstra[1976]. For more recent studies on modularity we refer the readers to Banerjee and Naumann[2005]; Leino and Müller[2005]. Averroes [Ali and Lhoták 2013] is a tool for generalizing call-graphs of applications by leaning on a separate compilation assumption to generate a general stub library for applications. This allows analysis tools to be modular, as generating full call-graphs is both expensive and imprecise. They show how encapsulation assumptions and proofs can be leveraged to improve the feasibility and the precision of analyses. In our work, we give a sufficient condition, ECF, for the ability to soundly reason about a single object in isolation from any other object. The work of Leino and Nelson[2002] presents an idiom for verifying if an object behaves as expected in the presence of callbacks, called Valid/state specification idiom. Every object o maintains a ‘valid’ bit that indicates if its state is valid, i.e., satisfies its object invariants. The bit should be true in every first invocation of o in an execution. When o calls a method of another object o′, o turns off its ‘valid’ bit. This way, if the execution of o′ leads to another method call of o, before the original call to o completed, the code of o can take into account the fact that its object invariants do not necessarily hold. The existence of such a ‘valid’ bit is helpful to achieve modular soundness, that is the ability to reason about an object in isolation. This paper achieves modular soundness by relying on the encapsulation of the object’s state. Essentially, an ECF object is an object for which the ‘valid’ bit is always turned on, as it is guaranteed that the object state changes only from within the object’s methods, and that those methods too are only executed where originally the ‘valid’ bit would be turned on. Thus, with the assumption on all executions being ECF, there is no need to define a separate behavior of the code for when the ‘valid’ bit is turned on or off. Toenablesound modular reasoning, we simply ignore external calls and assume any return value returned from any such external call. We note that the absence of shared state drastically simplify our life. Logozzo[2009] presents a method for modular inference of class invariants. Specifically, it is shown that the trace semantics of an isolated class are sound and complete with respect to the trace semantics of a whole program. The goal is to find the strongest state-based sound class invariant,

12The Ethereum blockchain suffered a DoS attack [Bok Consulting 2016b; StackExchange 2017] affecting the blockchain in the range of block numbers 2.2M-2.7M, causing all peers participating in the blockchain to make frequent accesses to disk. Running on a RAM disk was necessary to minimize the runtime of experiments. that holds in both the isolated and non isolated cases. Abstraction is used in order to compute such an invariant. If it the class invariant matches the specification of the class, then it is ensured that the class itself matches the specification even in the context of a whole program. The mentioned work enables modular reasoning by using abstraction. Our work does not attempt to find such a sound class invariant, but rather to satisfy the necessary conditions for being able to statically verify any specification of an object in isolation of other objects. The benefit here is that wedonot depend on the precision of an abstraction, which may output an invariant that overapproximates the specification, and thus does not meet it.

10.2 Verification of Smart Contracts Even before the events surrounding the bug in the DAO, there were discussions in the Ethereum community about formal verification of smart contracts. Following the extreme measures takento avert the effects of the attack on the DAO by hard-forking the blockchain and effectively rewrite its history of executions, the discussion became more wide-spread. Luu et al. [2016] characterized a class of security bugs in smart contracts called Transaction- Ordering Dependence (TOD). A contract inflicted with TOD bugs may behave unexpectedly when there is more than one client using the system and the effect of the execution of one client depends on whether the other client already executed or not. In both TOD and ECF the bugs arise from the fact that the execution is performed in an unexpected state of the contract. However, TOD bugs arise when there is more than one execution (since smart contracts are executed in a distributed environment), whilst non-ECF arises even in a single execution which contains callbacks. One of the solutions suggested for TOD bugs is guarded transactions. The idea is to allow contract writers to define guard conditions which are verified by the virtual machine executing the contract code. The execution must satisfy the guard condition, otherwise it fails without any effect. However, by enabling modular reasoning on contracts by proving or asserting at runtime that the executions are ECF, we can verify similar conditions statically. The only addition that may be required for the virtual machine is the online ECF check, which we found to be inexpensive in practice. Checking arbitrary conditions at runtime may either be inefficient, or not expressible enough to specify fully correct contract behavior. In addition, by verifying at runtime that executions are ECF, we are already able to detect and prevent executions which are, with high probability, unwanted or unexpected. Luu et al. [2016] presents a tool called Oyente [Melonport 2017], based on symbolic execution of contracts. The tool’s web version reports on the existence of ‘reentrancy bugs’, which is how the family of bugs such as the bug in the DAO were dubbed by the Ethereum community. We attempted to verify both ECF and non-ECF contract variations based on the DAO object presented in Figure1. We received a report on a ‘reentrancy bug’, even on ECF contracts. We reported the false positives to the web Oyente team, and will submit the issue request by the camera-ready deadline. The Why3 [Filliâtre and Paskevich 2013] tool was also applied to verify smart contracts written in Solidity. This requires whole code analysis and user supplied loop invariants. Bhargavan et al. [2016] translate a subset of the high-level Solidity language for Smart Contract development to F*, enabling using F*’s verification framework on Smart Contracts. They also presented a decompiler for EVM bytecode to F*. Similarly to the Why3 approach, the authors faced the issue of translating peculiar syntactic features of the smart contract language Solidity to F*. It should be noted that both F* and Oyente are successful in detecting other bugs, such as mishandled exceptions. For technical clarity, we omit discussion of the semantics of exceptions and rollbacks in Ethereum. Primarily, to arrive at general results that can be applied in domains other than Ethereum, and secondly, to not overbear the reader with technical details on the myriad ways Ethereum contracts may be invoked, and how exceptions may be handled in each of these ways. Delmolino et al. [2015] discuss their insights from an educational smart contracts lab they held, and published example contracts used in the lab. We manually analyzed one such contract, implementing a rock, paper, scissors game [Delmolino et al. 2016]. We identified several control paths in which a non-ECF execution might manifest. Specifically, there are two control paths in registration to the game (in which players provide a sum as bounty), and three additional paths in the collection of the prize. However, the authors put a constraint on the ability to execute callbacks by limiting to a minimum the amount of gas available to the execution. gas is a novel concept in Ethereum that effectively bounds the runtime by associating with each low-level opcode a cost. If an execution is not provided with enough gas when called, it throws a special out-of-gas exception. Sergey and Hobor[2017] offer an analogy between the nomenclature of Smart Contracts andthat of concurrent objects. Specifically, the scenario of a contract calling another contract is compared to cooperative multitasking, in which contract invocation is analogous to the case where the caller yields control. One of the main challenges mentioned is that of being able to verify contracts in isolation of other contracts. The ECF property brings us closer to that goal, by allowing to check properties that can be specified as ‘contract invariants’ in a modular way.

11 CONCLUSION In this paper we have presented a simple generic correctness condition for callbacks called Effective Callback Freedom and studied its usefulness. We have shown that it enables modular reasoning in environments with local-only mutable states like Ethereum. We have also shown that in Ethereum it can be used to prevent bugs without drastically limiting programming style, and that it can be checked dynamically with low runtime overhead. In the future, we expect to apply the concept of ECF and prove its usefulness in other environments such as Microservices and Amazon λ.

ACKNOWLEDGMENTS We would like to thank the reviewers for their helpful comments. The research leading to these results has received funding from the European Research Council under the European Union’s Seventh Framework Programme (FP7/2007-2013) / ERC grant agreement n◦ [321174], Len Blavatnik and the Blavatnik Family foundation, Blavatnik Interdisciplinary Cyber Research Center at Tel Aviv University, and the Pazy Foundation.

REFERENCES 2017. Validity Labs. https://validitylabs.org. (2017). [Online]. Karim Ali and Ondřej Lhoták. 2013. Averroes: Whole-program Analysis Without the Whole Program. In Proceedings of the 27th European Conference on Object-Oriented Programming (ECOOP’13). Springer-Verlag, Berlin, Heidelberg, 378–400. Ambisafe. 2017. Ethereum Asset Platform. https://www.ambisafe.co/. (2017). [Online; accessed 1-July-2017]. B9Lab. 2017. ING hack challenge. (2017). [Online]. Anindya Banerjee and David A. Naumann. 2005. Ownership confinement ensures representation independence for object- oriented programs. J. ACM 52, 6 (2005), 894–960. Philip A. Bernstein, Vassos Hadzilacos, and Nathan Goodman. 1987. Concurrency Control and Recovery in Database Systems. Addison-Wesley. Karthikeyan Bhargavan, Antoine Delignat-Lavaud, Cédric Fournet, Anitha Gollamudi, Georges Gonthier, Nadim Kobeissi, Natalia Kulatova, Aseem Rastogi, Thomas Sibut-Pinote, Nikhil Swamy, and Santiago Zanella-Béguelin. 2016. Formal Verification of Smart Contracts: Short Paper. In Proceedings of the 2016 ACM Workshop on Programming Languages and Analysis for Security (PLAS ’16). ACM, New York, NY, USA, 91–96. Bok Consulting. 2016a. The DAO ETC Drains. https://github.com/bokkypoobah/TheDAOETCDrains. (2016). [Online; accessed 2-July-2017]. Bok Consulting. 2016b. Ethereum Network Attacker’s IP Address Is Traceable. https://www.bokconsulting.com.au/blog/ ethereum-network-attackers-ip-address-is-traceable/. (2016). [Online; accessed 30-June-2017]. Ahmed Bouajjani, Javier Esparza, and Oded Maler. 1997. Reachability analysis of pushdown automata: Application to model-checking. CONCUR’97: Concurrency Theory (1997), 135–150. Vitalik Buterin. 2016. CRITICAL UPDATE Re: DAO Vulnerability. https://blog.ethereum.org/2016/06/17/ critical-update-re-dao-vulnerability/. (2016). [Online; accessed 2-July-2017]. Phil Daian. 2016. (2016). http://hackingdistributed.com/2016/06/18/analysis-of-the-dao-exploit/ Kevin Delmolino, Mitchell Arnett, Ahmed E. Kosba, Andrew Miller, and Elaine Shi. 2015. Step by Step Towards Creating a Safe Smart Contract: Lessons and Insights from a Cryptocurrency Lab. IACR Cryptology ePrint Archive 2015 (2015), 460. Kevin Delmolino, Mitchell Arnett, Ahmed E. Kosba, Andrew Miller, and Elaine Shi. 2016. Ethereum - Serpent Tutorial and Smart Contract Lab. https://github.com/mc2-umd/ethereumlab/blob/master/Examples/RPS_v2_new.py. (2016). [Online; accessed 2-July-2017]. Edsger W. Dijkstra. 1976. A Discipline of Programming. Prentice-Hall. Ethereum Classic. 2017. Ethereum Classic. https://etcchain.com/. (2017). [Online; accessed 2-July-2017]. Ethereum Foundation. 2017a. Geth. https://github.com/ethereum/go-ethereum/wiki/geth. (2017). [Online; accessed 30-June-2017]. Ethereum Foundation. 2017b. Solidity. https://solidity.readthedocs.io/en/develop/. (2017). [Online; accessed 5-July-2017]. Ethereum Reddit. 2016. From the MAKER DAO slack: "Today we discovered a vulnerability in the ETH token wrapper which would let anyone drain it.". https://www.reddit.com/r/ethereum/comments/4nmohu/from_the_maker_dao_slack_ today_we_discovered_a/. (2016). [Online; accessed 2-July-2017]. Etherscan. 2017. 0xbfBeA57d87E15529a30B6634C1C13F1A12Fa4d09. https://etherscan.io/address/ 0xbfbea57d87e15529a30b6634c1c13f1a12fa4d09. (2017). [Online; accessed 1-July-2017]. Jean-Christophe Filliâtre and Andrei Paskevich. 2013. Why3 — Where Programs Meet Provers. In Proceedings of the 22nd European Symposium on Programming (Lecture Notes in Computer Science), Matthias Felleisen and Philippa Gardner (Eds.), Vol. 7792. Springer, 125–128. Alexey Gotsman and Hongseok Yang. 2011. Liveness-Preserving Atomicity Abstraction. In Automata, Languages and Programming - 38th International Colloquium, ICALP 2011, Zurich, Switzerland, July 4-8, 2011, Proceedings, Part II. 453–465. C. A. R. Hoare. 1972. Proof of Correctness of Data Representations. Acta Inf. 1 (1972), 271–281. J.E. Hopcroft, R. Motwani, and J.D. Ullman. 2006. Introduction to automata theory, languages, and computation. Addison- wesley. Leslie Lamport. 1978. Time, Clocks, and the Ordering of Events in a Distributed System. Commun. ACM 21, 7 (July 1978), 558–565. K. Rustan M. Leino. 2010. Dafny: An Automatic Program Verifier for Functional Correctness. In Logic for Programming, Artificial Intelligence, and Reasoning: 16th International Conference, LPAR-16, Dakar, Senegal, April 25–May 1,2010, Revised Selected Papers, Edmund M. Clarke and Andrei Voronkov (Eds.). Springer, Berlin, Heidelberg, 348–370. https: //doi.org/10.1007/978-3-642-17511-4_20 K. Rustan M. Leino and Peter Müller. 2005. Modular Verification of Static Class Invariants. In FM 2005: Formal Methods, International Symposium of Formal Methods Europe, Newcastle, UK, July 18-22, 2005, Proceedings. 26–42. K. Rustan M. Leino and Greg Nelson. 2002. Data Abstraction and Information Hiding. ACM Trans. Program. Lang. Syst. 24, 5 (Sept. 2002), 491–553. Francesco Logozzo. 2009. Class Invariants As Abstract Interpretation of Trace Semantics. Comput. Lang. Syst. Struct. 35, 2 (July 2009), 100–142. Loi Luu, Duc-Hiep Chu, Hrishi Olickel, Prateek Saxena, and Aquinas Hobor. 2016. Making Smart Contracts Smarter. In Proceedings of the 2016 ACM SIGSAC Conference on Computer and Communications Security (CCS ’16). ACM, New York, NY, USA, 254–269. Melonport. 2017. Oyente. https://oyente.melonport.com. (2017). [Online; accessed 6-July-2017]. Satoshi Nakamoto. 2008. Bitcoin: A peer-to-peer electronic cash system. https://bitcoin.org/bitcoin.pdf. (2008). p-s-dev. 2016. Split DAOs. https://gist.github.com/p-s-dev/e940788a3472fefa1539b327b8628943. (2016). [Online; accessed 1-July-2017]. Johannes Pfeffer. 2016. The rise of the Dark DAO. https://medium.com/@oaeee/the-rise-of-the-dark-dao-72b21a2212e3. (2016). [Online; accessed 2-July-2017]. Rob Pike. 2012. Go at Google. In Proceedings of the 3rd Annual Conference on Systems, Programming, and Applications: Software for Humanity (SPLASH ’12). ACM, New York, NY, USA, 5–6. Ilya Sergey and Aquinas Hobor. 2017. A Concurrent Perspective on Smart Contracts. In 1st Workshop on Trusted Smart Contracts. Ethereum StackExchange. 2017. Why is my node synchronization stuck/extremely slow at block 2,306,843? https://ethereum. stackexchange.com/questions/9883/why-is-my-node-synchronization-stuck-extremely-slow-at-block-2-306-843. (2017). [Online; accessed 30-June-2017]. Nick Szabo. 1997. Formalizing and securing relationships on public networks. First Monday 2, 9 (1997). Validity Labs. 2017. Recursive call exploit. (2017). [Online]. Peter Vessenes. 2016. More Ethereum Attacks: Race-To-Empty is the Real Deal. http://vessenes.com/ more-ethereum-attacks-race-to-empty-is-the-real-deal/. (2016). [Online; accessed 2-July-2017]. Gavin Wood. 2016. Ethereum: A Secure Decentralised Generalised Transaction Ledger. http://gavwood.com/paper.pdf. (2016). [Online; accessed 5-July-2017].