formal specification and verification of smart contracts ... · specifications and verifications to...

21
Formal Specification and Verification of Smart Contracts for Azure Blockchain Shuvendu K. Lahiri Microsoft Research, USA shuvendu@microsoſt.com Shuo Chen Microsoft Research, USA shuochen@microsoſt.com Yuepeng Wang University of Texas, Austin [email protected] Isil Dillig University of Texas, Austin [email protected] Abstract In this paper, we describe the formal verification of Smart Contracts offered as part of the Azure Blockchain Content and Samples on github. We describe two sources of formal verifi- cation problems: (i) semantic conformance checking of smart contracts against a state-machine and access control based Azure Blockchain Workbench application configuration, and (ii) safety verification for smart contracts implementing the authority governance in Ethereum Proof-of-Authority (PoA) on Azure. We describe a new program verifier VeriSol for Solidity based on a translation to Boogie and leveraging the Boogie verification toolchain. We describe our experience applying VeriSol to Workbench sample contracts and Proof of Authority governance contracts in Azure, and finding previously unknown bugs in well-tested smart contracts. We provide push-button unbounded verification for the se- mantic conformance checking for all the sample contracts shipped in Workbench, once the bugs are fixed. 1 Introduction The advent of blockchain (decentralized and distributed con- sensus protocol to maintain and secure a shared ledger) is seen as a disruptive technology with far-reaching impact on diverse areas of society such as cryptocurrencies, banking, escrow and governance. According to the Microsoft’s Coco Framework white paper[29] Blockchain technology is poised to become the next transformational computing paradigm. It promises to disrupt existing business processes, to reduce the friction of doing business, and to unlock new business models, especially shared processes across organizations. According to Gartner, the business value-add of blockchain will grow to slightly more than $176 billion by 2025, and then it will exceed $3.1 trillion by 2030. Work done while employed as an intern at Microsoft. Work done while employed as visiting researcher at Microsoft. Conference’17, July 2017, Washington, DC, USA 2018. ACM ISBN 978-x-xxxx-xxxx-x/YY/MM. . . $15.00 hps://doi.org/10.1145/nnnnnnn.nnnnnnn Given such benefits, in our rapidly evolving dig- ital economy, it won’t be long before blockchain technology is a key foundation for distributed enterprise and consumer applications. Smart Contracts are applications that run on blockchains such as Ethereum, and are an essential ingredient for democ- ratizing the use of blockchain technology beyond cryptocur- rencies (e.g. bitcoin). Smart contracts often encode expressive workflows encoded in a Turing-complete programming lan- guage. For example, the Ethereum blockchain provides a low-level stack-based bytecode language that executes on top of the Ethereum Virtual Machine (EVM). High level lan- guages such as Solidity and Serpent have been developed to enable traditional application developers to author smart contracts. There are at least two compelling reasons to apply formal specifications and verifications to smart contracts: Smart contract vulnerabilities. Unlike traditional pro- grams written in high-level programming languages, smart contracts have unique security and integrity characteris- tics. First, smart contracts manage, hold, and transfer digi- tal assets such as Ether, which make them susceptible to theft. Second, smart contracts are mostly immutable after deployment and hence the need to ensure their safety and security operating in an open and adversarial context is of paramount importance. Vulnerabilities in smart contracts have resulted in several high-profile exploits that under- mine the trust in the underlying blockchain technology. For example, the infamous TheDAO exploit [2] resulted in the loss of almost 60 million USD worth of Ether, and resulted in an undesirable hard fork in Ethereum. Sev- eral other smart contract vulnerabilities have resulted in the loss of substantial value of Ether [15], including the Parity Wallet bug that resulted in 169 million USD worth of ether to be locked forever [5]. High-level specifications. Smart contracts are often low- level implementations of a high-level workflow that com- prises a state machine with different actions predicated by suitable access control to determine who has the permission to execute a given action. These high-level workflows are arXiv:1812.08829v1 [cs.PL] 20 Dec 2018

Upload: others

Post on 19-Oct-2020

7 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Formal Specification and Verification of SmartContracts for Azure Blockchain

Shuvendu K. LahiriMicrosoft Research, [email protected]

Shuo ChenMicrosoft Research, [email protected]

Yuepeng Wang∗University of Texas, [email protected]

Isil Dillig†University of Texas, Austin

[email protected]

AbstractIn this paper, we describe the formal verification of SmartContracts offered as part of the Azure Blockchain Content andSamples on github. We describe two sources of formal verifi-cation problems: (i) semantic conformance checking of smartcontracts against a state-machine and access control basedAzure Blockchain Workbench application configuration, and(ii) safety verification for smart contracts implementing theauthority governance in Ethereum Proof-of-Authority (PoA)on Azure. We describe a new program verifier VeriSol forSolidity based on a translation to Boogie and leveraging theBoogie verification toolchain. We describe our experienceapplying VeriSol to Workbench sample contracts and Proofof Authority governance contracts in Azure, and findingpreviously unknown bugs in well-tested smart contracts.We provide push-button unbounded verification for the se-mantic conformance checking for all the sample contractsshipped in Workbench, once the bugs are fixed.

1 IntroductionThe advent of blockchain (decentralized and distributed con-sensus protocol to maintain and secure a shared ledger) isseen as a disruptive technology with far-reaching impact ondiverse areas of society such as cryptocurrencies, banking,escrow and governance. According to the Microsoft’s CocoFramework white paper[29]

Blockchain technology is poised to become thenext transformational computing paradigm. Itpromises to disrupt existing business processes,to reduce the friction of doing business, and tounlock new business models, especially sharedprocesses across organizations. According toGartner, the business value-add of blockchainwill grow to slightly more than $176 billion by2025, and then it will exceed $3.1 trillion by 2030.

∗Work done while employed as an intern at Microsoft.†Work done while employed as visiting researcher at Microsoft.

Conference’17, July 2017, Washington, DC, USA2018. ACM ISBN 978-x-xxxx-xxxx-x/YY/MM. . . $15.00https://doi.org/10.1145/nnnnnnn.nnnnnnn

Given such benefits, in our rapidly evolving dig-ital economy, it won’t be long before blockchaintechnology is a key foundation for distributedenterprise and consumer applications.

Smart Contracts are applications that run on blockchainssuch as Ethereum, and are an essential ingredient for democ-ratizing the use of blockchain technology beyond cryptocur-rencies (e.g. bitcoin). Smart contracts often encode expressiveworkflows encoded in a Turing-complete programming lan-guage. For example, the Ethereum blockchain provides alow-level stack-based bytecode language that executes ontop of the Ethereum Virtual Machine (EVM). High level lan-guages such as Solidity and Serpent have been developedto enable traditional application developers to author smartcontracts.

There are at least two compelling reasons to apply formalspecifications and verifications to smart contracts:

• Smart contract vulnerabilities. Unlike traditional pro-gramswritten in high-level programming languages, smartcontracts have unique security and integrity characteris-tics. First, smart contracts manage, hold, and transfer digi-tal assets such as Ether, which make them susceptible totheft. Second, smart contracts are mostly immutable afterdeployment and hence the need to ensure their safety andsecurity operating in an open and adversarial context is ofparamount importance. Vulnerabilities in smart contractshave resulted in several high-profile exploits that under-mine the trust in the underlying blockchain technology.For example, the infamous TheDAO exploit [2] resultedin the loss of almost 60 million USD worth of Ether, andresulted in an undesirable hard fork in Ethereum. Sev-eral other smart contract vulnerabilities have resultedin the loss of substantial value of Ether [15], includingthe Parity Wallet bug that resulted in 169 million USDworth of ether to be locked forever [5].

• High-level specifications. Smart contracts are often low-level implementations of a high-level workflow that com-prises a state machine with different actions predicated bysuitable access control to determine who has the permissionto execute a given action. These high-level workflows are

arX

iv:1

812.

0882

9v1

[cs

.PL

] 2

0 D

ec 2

018

Page 2: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Conference’17, July 2017, Washington, DC, USA Shuvendu K. Lahiri, Shuo Chen, Yuepeng Wang, and Isil Dillig

often designed by domain experts, who may not be profi-cient programmers with knowledge of subtle semantics ofprogramming constructs. Thus, there is strong need for ahigh-level specification language for expressing the intentof the workflow, which can be implemented in a smartcontract. Specifying the high-level workflow abstractlyalso allows targeting different languages (e.g. Solidity) orledgers (Ethereum vs. Hyperledger Fabric [1]) with relativeease.In this work, we explore the use of formal specification

and verification for Solidity smart contracts that constitutethe Azure Blockchain content and samples on github [8]1.Azure Blockchain consists of a set of components and ser-vices that allow businesses to rapidly prototype and deployblockchain applications on the Azure cloud [4]. Among otherservices, it currently consists of two main products (a) AzureBlockchain Workbench (or simply Workbench henceforth),and (b) Ethereum on Azure, which are interesting from theperspective of smart contract analysis. Several aspects ofthese smart contracts make them interesting targets for veri-fication:1. First, many of the sample contracts constitute proof of

concepts for real-world enterprise scenarios.2. Second, a Workbench application consists of a JSON file

that expresses the state machine with access control thata smart contract has to implement. Once formalized, thesecan serve as implicit specifications that can be checkedstatically or at runtime.

3. Finally, the smart contracts that constitute the Ethereumon Azure (namely, the PoA governance contracts) havebeen deployed several thousand times byAzure Blockchaincustomers. Thus, the safety and security issues in suchcontracts have serious real-world consequences.Although several static analysis approaches have been

proposed recently to scan for known vulnerabilities in smartcontracts [27, 31], they do not offer the users the ability tospecify and verify formal specifications (see Related Workin Section 8 for further explanation). For the purpose of thispaper, we distinguish a formal verifier from static analysis inthat a violation of a formal specification is always considereda bug, not just a bad coding practice.

Contributions. The paper makes the following contribu-tions:1. We provide a formalization to the JSON-basedWorkbench

application configuration that allows formal tools to in-terpret and enforce it.

2. We define a semantic conformance checking problem be-tween a JSON-basedWorkbench application configuration

1The content of the paper is based purely on information available in opensource in the github page and Azure documentation pages. Moreover, giventhe static nature of the verification, we only need access to the JSON config-uration and Solidity smart contract source files for conducting this study.

and a smart contract, and provide an automatic programinstrumentation to enforce the specification in a Soliditysmart contract.

3. We describe a new prototype formal verifier VeriSol forSmart Contracts written in Solidity. The verifier encodesthe semantics of Solidity programs into Boogie and lever-ages the well-engineered Boogie verification pipeline [16].The verifier is generic and not tied to the Azure Blockchainexamples.

4. We useVeriSol to discover previously unknown semanticconformance bugs inWorkbench samples using transaction-bounded verification; we then report full verification of theproperty on the fixed examples using invariant inference.

5. Finally, we report a detailed case study of VeriSol on aPoA governance contract in Azure Blockchain and findpreviously unknown bugs.

Organization. The paper is organized as follows: In Sec-tion 2, we provide an overview of the Azure Blockchaincomponents and the smart contracts available as part ofAzure Blockchain Content and Samples; we introduce a sim-ple running example and informally describe the WorkbenchJSON application configuration language for specifying ac-cess control and state transitions. In Section 3 we provideformal semantics for the Workbench JSON application con-figuration (Section 3.1). In Section 4 we describe the problemof semantic conformance for a smart contract C implement-ing a Workbench JSON configurationW . In Section 5, weprovide an encoding of a subset of the Solidity language inBoogie intermediate verification language. In Section 6, wedescribe a formal verifier VeriSol for Solidity, that lever-ages the Boogie translation and uses various Boogie based(bounded and unbounded) verification tools. In Section 7,we provide our experience of running VeriSol on the smartcontracts that constitute the Azure Blockchain.We discussrelated work in Section 8 and finally conclude.

2 Overview of Azure Blockchain Contentand Samples

Azure Blockchain consists of a set of components and ser-vices that allow businesses to rapidly prototype and deployblockchain applications on the Azure cloud. Among otherservices, it currently consists of two products that are some-how independent (a) Azure Blockchain Workbench, and (b)Ethereum on Azure, which are interesting from the perspec-tive of smart contract analysis. Azure Blockchain Work-bench is primarily focused on the application level, whereasEthereum on Azure is a product offering at the ledger level.This section gives an overview about the two.

2.1 Azure Blockchain WorkbenchWorkbench consists of services that allow users to deployblockchain applications on the Azure cloud. An enterprisesmart contract application requires not only a bare ledger,

Page 3: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Formal Specification and Verification of Smart Contracts for Azure BlockchainConference’17, July 2017, Washington, DC, USA

Figure 1. Workflow diagram for HelloBlockchain application.

but also services for user authentication, identity mapping,messaging, REST APIs, web UI, source code control, etc.Azure Blockchain Workbench (abbr. Workbench) is a prod-uct that allows such an application scaffold to be created onAzure very easily, so that a user can focus on building thesmart contract application. In Workbench, the smart con-tract application consists of two components: (i) a JSON filedescribing the application configuration or interface2, and(ii) a smart contract that implements the application busi-ness logic. Once an application is uploaded into Workbench,users can add more members, and members can drive theapplication to different states by taking suitable actions. Weinformally describe the configuration language (formallydescribed in Section 3.1) and an associated Solidity smartcontract in the next few paragraphs.

2.1.1 Workbench Application ConfigurationWorkbench requires a JSON based configuration file thatis used to populate the application information, which canbe queried by users through REST APIs to interact with aWorkbench application. The JSON interface of an applicationconsists of several attributes such as application name anddescription, set of roles, alongwith a set ofworkflows. Figure 1provides an informal pictorial representation of the JSON fora simple application called HelloBlockchain. The actualJSON and the example related details can be found on theassociated web page3. The application consists of two roles(refereed under “APPLICATIONROLES”) namely Reqestorand Responder. Informally, each role represents a set ofuser addresses; roles are used to provide access control orpermissions for various actions exposed by an application.

2We use the terms configuration and interface interchangeably.3https://github.com/Azure-Samples/blockchain/tree/master/blockchain-workbench/application-and-smart-contract-samples/hello-blockchain

A workflow informally consists of a name, descriptionalong with a set of states, data members, functions (or ac-tions), and state transitions. The simple HelloBlockchainapplication consists of a single workflow with the samename as the application. As seen from Figure 1, the work-flow consists of two states: Request and Respond. Thedata members (or fields) consists of Requestor, Responderthat range over addresses, and strings RequestMessage andResponseMessage to store the last message (not shown inthe figure). The workflow consists of two actions or functionsin addition to the constructor function: SendRequest andSendResponse, both of which take a string as argument.

Finally, the state transitions specify the initial state (Requestfor this example) and the transitions between the states. Atransition consists of a start state, an action or function, anaccess control list, and a set of successor states. Figure 1describes two transitions, one from each of the two states.For example, the application can transition from Requestto Respond if a user from the Reqestor (categorized as“Allowed Role” (AR) under “Legend” box) invokes the actionSendResponse. An “Application Instance Role” (AIR) refersto a data member of the workflow that stores a member ofa global role (also called Requestor for the example) — atransition such as from Respond to Request that uses anAIR checks if the user address matches the value stored inthe instance data variable.

2.1.2 Workbench Application Smart ContractAfter specifying an application configuration in JSON, a userprovides a smart contract for the appropriate blockchainledger to implement the workflow. Currently, Workbenchsupports the popular language Solidity for targeting appli-cations on Ethereum. Figure 2 describes a Solidity smartcontract that implements the HelloBlockchain workflowin the HelloBlockchain application. For the purpose ofthis section, we will ignore the portions of the code that are

Page 4: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Conference’17, July 2017, Washington, DC, USA Shuvendu K. Lahiri, Shuo Chen, Yuepeng Wang, and Isil Dillig

pragma solidity ^0.4.20;

contract HelloBlockchain

//Set of States

enum StateType Request, Respond

//List of properties

StateType public State;

address public Requestor;

address public Responder;

string public RequestMessage;

string public ResponseMessage;

// constructor function

function HelloBlockchain(string message)

constructor_checker()public

Requestor = msg.sender;

RequestMessage = message;

State = StateType.Request;

// call this function to send a request

function SendRequest(string requestMessage)

SendRequest_checker() public

RequestMessage = requestMessage;

State = StateType.Request;

// call this function to send a response

function SendResponse(string responseMessage)

SendResponse_checker() public

Responder = msg.sender;

ResponseMessage = responseMessage;

State = StateType.Respond;

<modifier definitions>

Figure 2. Solidity contract for HelloBlockchain application.

underlined — we will refer to them when describing theconformance checking in Section 4.2. The contract declaresthe data members present in the JSON configuration as statevariables with suitable types. Each contract implementing aworkflow defines an additional state variable State to trackthe current state of a workflow. The contract consists of theconstructor function along with the two functions definedin the JSON configuration, with matching signatures. Thefunctions set the state variables and update the state variableappropriately to reflect the state transitions.

The Workbench service allows a user to upload the JSON,the Solidity code, and optionally adding users and performvarious actions permitted by the configuration. To ensurethe correct functioning and security of the application, itis crucial to verify that the Solidity program semanticallyconforms to the intended meaning of the JSON configuration.

2.2 Proof of Authority Governance ContractsSeparate from the application level Workbench offering,Azure Blockchain also offers ledger level services. One ofthem is Ethereum on Azure. The Ethereum blockchain comes

with a choice of consensus protocols for a decentralized sys-tem: (i) the conventional Proof of Work (PoW) and the (ii)the Proof of Authority (PoA). The consensus algorithm hasto decide which node wins the privilege to append the latestblock to the blockchain.The PoW is the widely used consensus algorithm for tra-

ditional public (permissionless) blockchain to guard againstSybil attacks in the presence of anonymous nodes, e.g., inthe BitCoin network. A malicious party could easily createmany nodes to be disproportionately powerful. However,PoW consensus is computationally expensive as it relies onminers solving a difficult cryptographic puzzle, and thereforeit limits the throughput (the number of transactions that canbe mined per unit of time) of the blockchain network.

Figure 3. POA Ethereum on Azure and its governance con-tracts.

The PoA is proposed as an alternative to PoW for permis-sioned consortium networks where the identities cannot beforged, as they are linked to off-chain identities. It differsfrom a public blockchain in that the consortium is formedby running an election to accept new members, each havingan identity. The members share the responsibility/authorityof validating transactions and appending them in the ledger.It allows for a superior throughput in the case of consortiumblockchain applications.Enterprise customers and other systems such as Azure

Blockchain Workbench can deploy a PoA network on Azurebased on the Parity implementation of Ethereum. The net-work consists of a set of nodes running the PoA protocoland validating transactions. Every node is assigned a dis-tinct Ethereum address, which is called the validator address.The validator set is a contract managing a set of validatoraddresses (shown as "validators" for brevity). Adding or re-moving a validator address will result in its correspondingnode to be added into or removed from the PoA network.Parity Ethereum implementation exposes a ValidatorSet

contract interface that is implemented by the Ethereum on

Page 5: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Formal Specification and Verification of Smart Contracts for Azure BlockchainConference’17, July 2017, Washington, DC, USA

Azure deployment. Governing a PoA network requires aset of contracts shown in Figure 3. Validators belong to dif-ferent organizations, such as companies A, B and C in thefigure. Each organization is represented by an admin con-tract. Initially, the PoA network is created by one admin,who naturally becomes the only elected admin of the net-work. Later, for another admin to become an elected admin,it needs to win a majority vote among existing elected ad-mins. An elected admin is allowed to bring in a number ofvalidators. The admins can also vote against each other. Ifmore than half of the existing elected admins vote againstone of them, the admin will be evicted, and its validatorsare removed consequently. The above protocol for adminvoting and validator set management is implemented as aset of contracts that implement the Parity Ethereum’s Val-idatorSet contract interface, and available as part of AzureBlockchain content and samples [9, 10]. It consists of thefollowing smart contract implementations totaling around600 lines of Solidity code.• SimpleValidatorSet: A simple implementation of the Val-idatorSet that handles adding validators .

• AdminValidatorSet: Inherits from SimpleValidatorSet,and introduces the concept of Admins for different orga-nizations and voting. It allows an admin to control theirvalidator set and vote for other admins.

• Admin: A contract representing a Consortium member;it tracks votes for or against a given member.

• AdminSet: Contract used for performing constant timeoperations on a set of Admins.The smart contracts use several features that make it a

challenging benchmark for Solidity smart contract reasoning.We outline some of them here:• The contracts use multiple levels of inheritance since thetop-level contract AdminValidatorSet derives from thecontract SimpleValidatorSetwhich in turn derives fromValidatorSet interface.

• It uses sophisticated access control using Soliditymodifiersto restrict which users and contracts can alter states ofdifferent contracts.

• The contracts maintain deeply nestedmappings and arraysto store the set of validators for different admins.

• The contracts make use of nested loops and proceduresto iterate over the arrays, and make use of arithmeticoperations to reason about majority voting.

3 Formalizing Workbench ApplicationConfiguration

In the next couple of sections we describe the problem ofensuring that a smart contract C correctly implements theWorkbench Application Configuration provided in the JSONfile. We first formalize the Workbench Application Config-uration (WBAC) that we informally introduced in Section 2.The description can be seen as a mathematical representation

of the official schema documentation of WBAC as describedby the Azure Blockchain4.

3.1 Workbench Application InterfaceThe Workbench Application Interface (WBAC) is describedin a JSON file. The WBAC for an application allows the userto describe the data members of an applications, role-basedaccess control for various functions or actions, and finallya high-level state-machine based view of the application.The role-based access control provides security for deploy-ing smart contracts in an open and adversarial setting; thehigh-level state machine naturally captures the essence ofa workflow that progresses between a set of states based onsome actions from the user.

We assume that each function is associated with a sender ,which is the address of a user or another workflow thatinvokes the function. In Solidity, this is denoted by msg.senderparameter within a function. The invocation of a functioncan be restricted to users that belong to certain roles — werefer to this as the access control.

Formally, aWorkbenchApplication ConfigurationApp(R ,W,T)consists of the following:• A set of global roles R , common to all workflows, that isused for access control for functions.

• A set of types T, which can either be an (i) integer , or a (ii)string, or an (iii) an address of a contract or user, or a (iv)a role r ∈ R , or a (v) workflow w ∈ W (as defined next).

• A set of workflowsW, where a workflow w ∈ W is a tuple⟨Sw , s0w ,Pw ,Qw ,Fw ,ACw , ac0w ,γw⟩:– Sw , a bounded set of states,– s0w ∈ Sw , an initial state,– Pw , a set of properties where a property (id : t) ∈ Pwhas a type t ∈ Tand a string identifier id .

– A subset of propertiesQw ⊆ Pw are instance roles, wherethe types are roles from R . That is, for any (id : t) ∈Qw , t is a member of R . The intuition is that a specificinstance of a workflow may designate only a subset ofmembers from a given role to execute certain action. Theinstance role variables capture such instance specificusers who are members of a given role t ∈ R .

– A set of function types Fw , where each function typef(id0 : t0, . . . , idk−1 : tk−1) ∈ Fw consists of∗ The function name f,∗ Empty list of return parameters,∗ An arity k ≥ 0 of the input parameters,∗ A type ti ∈ Tand an identifier idi for the i-th param-eter (i ∈ [0,k)), counting from zero.

– A constructor type w(x0 : t0, . . . , xk−1 : tk−1) ∈ Fwwhere the function name equals the workflow name.

– The access control set ACw Qw ∪ R is a set over theunion of the instance role properties Qw and the set of

4https://docs.microsoft.com/en-us/azure/blockchain/workbench/configuration

Page 6: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Conference’17, July 2017, Washington, DC, USA Shuvendu K. Lahiri, Shuo Chen, Yuepeng Wang, and Isil Dillig

global roles in R . One can restrict the invocation of afunction within a transition by insisting that the senderbelongs to a subset of ACw .

– The initiator access control ac0w ⊆ R for restricting userswho can create an instance of the contract by callingthe constructor.

– Finally, a set transitions γw ⊆ Sw × Fw × AC × 2Sw .Intuitively, a transition (s1, f, acw ,S2) ∈ γw indicatesthe system can transition from state s1 to one of statesin S2 ⊆ Sw (non-deterministically) by invoking thefunction f ∈ Fw provided the “sender” of f is a memberof the access control set acw .

3.2 ExampleConsider the WBAC for the HelloBlockchain applicationdescribed in Section 2:• Set of roles R Reqestor, Responder• Set of typesT Reqestor,Responder ∪ integer, string ∪HelloBlockchain

• A single workflow W HelloBlockchain (we dropthe w suffix) with:– Set of workflow states S Request, Respond,– The start state s0 Request,– The set of properties (or fields)P RequestMessage :string, ResponseMessage : strinд, Requestor : Reqestor,Responder : Responder.

– The set of instance role properties areQ Requestor :Reqestor, Responder : Responder ⊆ P.

– The set of 3 functions:∗ The constructor HelloBlockchain(message : string),∗ Two functions SendRequest(requestMessage : string)and SendResponse(responseMessage : string).

– The access control setAC Requestor, Responder∪Reqestor,Responder, with the initiator access con-torl ac0 Reqestor.

– Finally, there are two state-transitions in γ as depictedin Figure 1.∗ (Request, SendResponse, Responder, Respond),and

∗ (Respond, SendRequest, Requestor, Request).

4 Semantic Conformance Checking forWorkbench

Given a WBAC App in the form of a JSON file and a smartcontract C (say a Solidity file), we would like to ensure thatthe smart contract C correctly implements the interface andthe state transitions described inW . This is crucial to ensurethat the high-level workflow specified in the application con-figuration file App by the designer is correctly implementedin the smart contract.

We can divide this task into (a) structural and (b) semanticconformance checking. The structural conformance check-ing ensures that the data members, states and types specified

inW match those inC . The semantic conformance checkingensures that the smart contract C (that is structurally con-formant with App) correctly implements the access controland state transitions inW . Whereas the structural checkingproblem can be stated purely in terms of the abstract syntaxtree of C , the semantic checks require reasoning over thedynamic runtime states of C . In Section 4.1, we formalizethe problem of semantic conformance by providing an ax-iomatic semantics over an abstract smart contract language.Next, we describe a program instrumentation technique forruntime enforcement of these checks, and provide a concreteimplementation for Solidity based smart contracts.We first state an abstract version of structural confor-

mance checking in this Section — the concrete details relyon the choice of language in which the smart contract isexpressed (e.g. Solidity). Given a WBAC App(R ,W,T) anda smart contract C , the structural conformance checker en-forces the following for each workflow w ∈ W: (i) Thereexists a contract or class named w inC , and the the matchedclass forw contains (a) amember variable named Statewhoserange is w.S, the set of states in w, (b) a matching membervariable or field for each p ∈ w.P with compatible types,and a matching constructor function and public functionsthat match the constructor and the functions in the work-flow. Each function needs to have matching name as wellas matching parameter name list, with compatible types.The Workbench system already provides one such structuralconformance checker for Solidity.

4.1 Semantic ConformanceIn this section, we show how to ensure that a structurallyconformant smart contract implements the access controland state transitions according to the WBAC specification.We formalize these checks using an axiomatic semanticsfor a generic smart contract that supports constructors andfunction invocation. We use the Floyd-Hoare triple notationfor partial correctness

ϕc

ψ to denote that for any execution σ of the statement c from astate satisfying the predicate ϕ, σ does not fail any assertionsand, upon termination, will end up in a state satisfying thepredicate ψ . We do not require the execution to terminatehowever.Let x be an instance of workflow w . At a high-level, the

idea is simple: we insist that when a function (respectively,the constructor) is executed along a transition (respectively,during contract creation), the resulting state transition shouldbe in accordance with the workbench application specifica-tion.1. Constructor. We ensure that a successful termination

of the constructor (of arity k) during the creation of an

Page 7: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Formal Specification and Verification of Smart Contracts for Azure BlockchainConference’17, July 2017, Washington, DC, USA

instance of the workflow by a user (sender) with the ap-propriate access control ac0w results in establishing theinitial state s0w .

¬isUser (sender) ∨ sender ∈ ac0w x .w(v1, . . . ,vk )x .State = s0w

We use a predicate isUser that checks if an address onblockchain refers to an user address or the address of acontract; the exact implementation would depend on theparticular choice of language in which a smart contract isexpressed. We weaken the access control check sender ∈ac0w with the predicate ¬isUser (sender) to indicate thatthe access control applies only to user addresses (and notto the address of contracts). There are sample contracts inWorkbench (e.g. BazaarItem [7]) that expect a contractinstance to be only created by another contract to enforcesome encapsulation, and not be created directly by an user.This is achieved by specifying ac0w to be the empty set.

2. Transition Functions. For a transition (s1, f, acw ,S2) ∈γw we ensure that if f (with arity k) is invoked from thestate s1 of the transition by a user in acw , then the stateof the smart contract instance transitions to one of thesuccessor states in S2.

sender ∈ acw ∧ x .State = s1x .f(v1, . . . ,vk )x .State ∈ S2

The precondition checks two facts: (i) the sender satisfiesthe access control and thus is a user address and (iii) thestart state is s1.

Type invariant. In addition to these two checks, one canalso postulate a type invariant for any instance role variableid of role type r . One can check that whenever such an in-stance role variable id holds a non-zero value (i.e. otherthan 0x0), then it is an address that is a member of theglobal role r ; recall that a global role (such as Reqestor inHelloBlockchain) denotes a dynamic list of addresses thatcan be added or removed by a Workbench application owner.However, such a check (id ∈ r ∪ 0x0 ) is really a precon-dition that is asserted at (i) entry to any public method, and(ii) after any assignment to id in the method body. We thinkof this as a precondition since the value of this predicatedepends on the contents of r , which can be seen as an inputto a function. Since it does not add any runtime assertionsto verify statically, we omit this check in our conformancechecking.

4.2 Semantic Conformance for SolidityIn this section, we provide a concrete implementation of thesemantic conformance checking for smart contracts writtenin the popular Solidity language for the Ethereum blockchain.We first describe a challenge in enforcing the checks related

to global roles. We then provide program instrumentationto add the conformance checks for ensuring correct initialstate and state transitions.

4.2.1 Global RolesAlthough a Workbench Application configuration declaresa set of global roles in R , Workbench currently does notmaintain the information on the blockchain. Workbenchmaintains the membership of different roles in databasesoutside of the blockchain. As a result, Solidity smart con-tracts for a Workbench application cannot refer to globalrole information in the body of any function. Validations ofaccess control in AC for a transition is performed by theWorkbench system directly at the time a function is invoked.This poses an interesting dilemma for statically verifyingthe semantic conformance: we can either model the state ofthe role database in addition to the smart contract code, orwe perform a conservative verification where the content ofeach global role is completely non-deterministic. We adoptthe latter for two reasons: (i) First, since the smart contractscannot refer to global roles in current Workbench, any mod-ification to the set of global roles (e.g. adding a user to theReqestor in the HelloBlockchain application) will neverbe interleaved with a transaction that executes a functionin a workflow (given the deterministic execution semanticsof EVM). (ii) Second, given that the global roles can changearbitrarily before invoking a function, one has to assume acompletely non-deterministic value of the global roles forsoundness. Therefore, we do not introduce any spurious be-haviors by assuming the global roles as being completelyarbitrary sets.

4.2.2 Program InstrumentationTo instrument the checks we formalized in the prior section,we use the modifier construct from Solidity. A modifierhas syntax very similar to a function definition in Soliditywith a name and list of parameters and a body that can referto parameters and globals in scope. The general structure ofa modifier definition without any parameters (we refer usersto Solidity documentation of modifiers [3]) is:

modifier Foo()

pre-statements;

_; // placeholder

post-statements;

where pre-statements and post-statements are Solid-ity statements. When this modifier is applied to a functionBar,

function Bar(int x) Foo()

Bar-statements;

Page 8: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Conference’17, July 2017, Washington, DC, USA Shuvendu K. Lahiri, Shuo Chen, Yuepeng Wang, and Isil Dillig

the Solidity compiler transforms the body of Bar to executepre-statements (respectively, post-statements) before(respectively, after) Bar-statements. This provides a con-venient way to inject code at multiple return sites from aprocedure and also inject code before the execution of theconstructor code (since a constructor may invoke other baseclass constructors implicitly).

We now define a couple of helper predicates before describ-ing the actual checks. Let us first define a Solidity predicateπ (ac) to encode a sender to be a member of an access-controlset ac :

π (ac)

false, ac = msg.sender == q, ac = q ∈ Qw NonDetFunc() ac = r ∈ Rπ (ac1) ∨ π (ac2) ac = ac1 ∪ ac2

Here NonDetFunc is a side-effect free Solidity function thatreturns a non-deterministic Boolean value at each invocation.For the sake of static verification as we describe in this pa-per, one can declare a function without any definition. Thisallows us to model the membership check sender ∈ ac con-servatively in the absence of global roles on the blockchain.However, this solution is not suitable for installing actual run-time checks since a truly non-deterministic function suchas NonDetFunc cannot be realized; we discuss the actualruntime checks in the Appendix A.

Next, we define a predicate for membership of a contractstate in a set of states S ⊆ Sw using α(s) as follows:

α(S)

false, S = State == StateType.s, S = s ∈ Sw α(S1) ∨ α(S2), S = S1 ∪ S2

We use these predicates to define the source code trans-formations below:• Constructor. For a workflow w, we add the followingmodifier to constructor.modifier constructor_checker()

require (msg.sender , tx.origin ∨ π (ac0w ));_;

assert (α (s0w ));

It is not hard to see that the assertion ensures that the con-structor sets up the correct intial state. The preconditionconsists of two parts. The first disjunct msg.sender ,tx.origin checks that the constructor is invoked by an-other contract and not a user (the global variable tx.origintracks the user address that initiates a transaction); thisis an implementation of the ¬isUser (sender) predicateabstractly stated in earlier section. The second disjunctπ (ac0w ) checks the access control for the msg.sender forthe case when it is a user address.

• Transition Function For a function g, let there be mul-tiple transitions γ g t ∈ γw | t .f == g where g isinvoked. Let k be the arity of g.

modifier g_checker()

// copy old State

StateType oldState = State;

// copy old instance role vars

...

_;

assert∧t∈γ g

(old

(π (t .acw ) ∧ α (t .sw )

)⇒ α (t .Sw )

);

First, we copy the State variable and all of the variablesin Qw into corresponding “old” copies. Next, the asser-tion checks that if the function is executed in a transitiont , then state (denoted by State) transitions to one of thesuccessor states in t .S. The notation old(e) replaces anyoccurrences of a state variable (such as State) with the “old”copy that holds the value at entry to the function; this isrequired since the value of the state variables can changeduring the execution of the procedure. Finally, since con-junction distributes over assertions, we can replace thesingle assertion with an assertion for each transition inthe implementation.

4.2.3 Instrumented Running ExampleFigure 4 shows themodifier definitions for our running exam-ple HelloBlockchain described in Section 2. The modifiersare applied to the user-written smart contract in Figure 2,and shown by the underlined statements. We add a com-ment for the lines where a reference to a global role in thespecification is replaced by a call to the non-deterministicfunction NonDetFunc.

function NonDetFunc() returns (bool); //no definition

// Checker modifiers

modifier constructor_checker()

require (msg.sender != tx.origin ||

NonDetFunc()); // global role REQUESTOR

_;

assert (State == StateType.Request);

modifier SendRequest_checker()

StateType oldState = State;

address oldRequestor = Requestor;

_;

assert ((msg.sender == oldRequestor &&

oldState == StateType.Respond)

==> State == StateType.Request);

modifier SendResponse_checker()

StateType oldState = State;

_;

assert ((NonDetFunc() && // global role RESPONDER

oldState == StateType.Request)

==> State == StateType.Respond);

Figure 4. Modifier definitions for instrumented Hel-loBlockchain application.

Page 9: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Formal Specification and Verification of Smart Contracts for Azure BlockchainConference’17, July 2017, Washington, DC, USA

5 Encoding SolidityIn the next two sections, we describe the design of a formalverifier for Solidity smart contracts. In this section, we firstdescribe a translation of Solidity program to a program inthe Boogie intermediate verification language [16]. Boogiehas a small language with formalized semantics, such thatverification tasks can be encoded into a formula in Satis-fiability Modulo Theory (SMT), and can be discharged bySMT solvers such as Z3 [19]. The ability to go from a Boogieprogram to a SMT formula allows us to leverage variousbounded and unbounded verification techniques for Boogie.

5.1 BoogieWe first describe a small subset of Boogie language that weuse to formalize our translation from Solidity.

Boogie types are integers (int), references (Ref ) or arrays;arrays can be nested in that each index of an array can storean array. Booleans are syntactic sugar over integers.

bbt ∈ BoogieElemTypes ::= int | Refbt ∈ BoogieTypes ::= bbt | [bbt]bt

e ∈ Exprs ::= c | x | op(e, . . . , e) | x[e] | ∀i : bbt :: est ∈ Stmts ::= skip | havoc x | x := e | x[e] . . . [e] := e |

assume e | assert e |call ®x := f(e, . . . , e) | st; st |if (e) st else st | while (e) do st

Figure 5. Simple subset of Boogie language.

Figure 5 describes the expressions and statements in thelanguage. Expressions (Exprs) consist of constants, variables,operations over expressions and array lookups, and quan-tified expressions. Expressions can have one of the Boogietypes described above, except ∀ expressions that have typeBoolean. Standard statements (Stmts) in Boogie consist ofskip (skip), variable and array assignment, sequential com-position, conditional statements, and loops. The havoc xstatement assigns an arbitrary value of appropriate type toa variable x. A procedure call (call ®x := f(e, . . . , e)) can re-turn a vector of values that can be stored in local variables.The assert and assume statements behave as skip when thethe Boolean valued argument evaluates to true in the state.When the argument evaluates to false, then assert fails theexecution and assume blocks the execution.A state σ ∈ Σ is a valuation of variables in scope. Eval-

uation of an expression e ∈ Exprs, is denoted by ⟨e⟩σ , anddefined inductively. We can define the standard operational(big-step) semantics σ1 ⊢ st ⇓ σ2 that denotes that execut-ing a statement st ∈ Stmts in a state σ1 can transition to astate σ2. We skip the details for the sake of brevity in thisdocument.

5.2 SolidityWe now define a subset of Solidity language that is suffi-ciently expressive and yet concise enough to demonstratethe translation.

5.2.1 TypesWe start with the set of Solidity types. Solidity types can beone of integer, string, address, a contract name, mappings orarrays over them. We unify a mapping type mapping(t1 =>t2) and an array type t2[t1] in Solidity as t1⇒ t2, wheret2 could be a nested array. In general, we use the Soliditytype t1 ⇒ t2 ⇒ . . . tk ⇒ t to stand for t1 ⇒ t (for k = 1)and t1 ⇒ (t2 ⇒ (. . . (tk ⇒ t)) . . .) (for k > 1).

ct ∈ ContractNameset ∈ SolElemTypes ::= integer | string | addressst ∈ SolTypes ::= et | ct | et ⇒ st

We define a mapping µ : SolTypes → BoogieTypes thattranslates a Solidity type to a type in Boogie as follows:

µ(st)

int, st ∈ integer, stringRef , st ∈ address ∪ ContractNames[µ(et)]µ(st), st et ⇒ st

As described later, we represent a Solidity string as an un-interpreted integer in Boogie. Solidity by default treats astring as an uninterpreted value that can only be comparedfor equality.

5.2.2 VariablesTo model the semantics of an object-oriented language suchas Solidity, each generated Boogie program consists of a setof variables in global scope:

• An array DType : [Ref]ContractNames that maps anaddress to a contract name corresponding to its dy-namic type.

• An array Alloc : [Ref]bool that maps an address toits allocation status.

• An array Length : [Ref]int that maps the address (ofan array) to the size of the array.

• For each scalar state variable F of type t in a contractC ∈ ContractNames in Solidity, we introduce a mapF_C : [Ref]µ(t).

• For an array or mapping state variable F, we introducea map F_C : [Ref]Ref .

• For any array type t1 ⇒ . . . ⇒ tk ⇒ t ∈ SolTypes(either as state variable or local variable) (where ti ∈SolElemTypes for i ∈ [1,k]), we add a set of maps:– M_bk_b : [Ref][µ(tk )]µ(t), and– a set of at most k − 1 distinct maps:

M_bi_Ref : [Ref][µ(ti )]Ref | i ∈ [1,k − 1]Here bk (respectively b) is the string representationof µ(tk ) (respectively µ(t)); for example, if µ(tk ) isint, then bk is “int”.

Page 10: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Conference’17, July 2017, Washington, DC, USA Shuvendu K. Lahiri, Shuo Chen, Yuepeng Wang, and Isil Dillig

Consider the example contracts in Figure 9 to illustratethe modeling.• First, for the state variable a in contract C of scalar type A ∈ContractNames, we introduce a map a_C of type [Ref]Ref ;an access to a inside a contract instance is treated asa_C[this]. Here this is a parameter to the enclosingmethod to refer to the address of the current object orcontract instance (corresponds to Solidity this).

• Second, since there is an array type int ⇒ int ⇒ int ∈SolTypes in the program as the type of n in contract A, weintroduce the maps M_int_Ref: [Ref][int]Ref andM_int_int:[Ref][int]int.

• An array access in Solidity such as n[0][0] is translate as

M_int_int[M_int_Ref[n_A[this]][0]][0]

where n_A[this] looks up the value of n for this instance,M_int_Ref[n_A[this]][0] looks up the map at index0, which is finally used to index into the M_int_Ref mapagain at index 0 to obtain the scalar value. We define theformal translation of expressions later in this section.In addition to the set of globals, the set of variables in local

scope consists of• A formal parameter x of type µ(t) for each solidityparameter x of type t .

• A formal parameter msg_sender of type Ref , and aformal parameter this of type Ref . These variablemodels the implicit Solidity parameters msg.senderand this respectively.

• A local variable x of type µ(t) for each Solidity localvariable x of type t .

5.2.3 ExpressionsFigure 10 describes the set of Solidity expressions (SolExprs).Most expressions are standard; the expression x.lengthrefers to the length of a static or dynamically allocated ar-ray x. Figure 11 describes translation of a Solidity expres-sion (denoted by the function Γ() : SolExprs → Exprs) toan expression in Boogie. We highlight the non-trivial caseshere. For a string literal, we use an uninterpreted functionStrToInt() to map it to an integer; one can think of this as ahash of the string. For a state variable x in contract C , thetranslation Γ(x) indexes into x_C with the this parameter.The translation of array access x[se] indexes into a globalarray after recursively translating x and se. The choice ofarray depends on the Solidity type of x[se]. If the Soliditytype is an array then the resulting expression has type Refin Boogie to represent the address of such an array; we indexinto the array M_t_Ref. Otherwise, we index into the arrayM_t_t2 where t2 is the translated type of x[se].

5.2.4 StatementsFigure 10 also describes the set of statements in Solidity thatwe translate to Boogie. The require(se) aborts execution

when executed in a state when se is false, and can be used foradding preconditions to functions. In contrast, assert(se)is used to terminate execution when an internal invariantse does not hold. We distinguish between two types of pro-cedure calls (a) internal call x = Foo(®e) which invokesa method Foo within the same contract, and (b) externalcall x = y.Foo(®e) that invokes a method on a contract in-stance pointed to by y (which may include this). For anarray variable x, x.push(se) adds an element with value seto the end of the array and increments the x.length. Wesupport two types of dynamic allocation (i) creation of anew contract instance of type C through x = new C( ®se)and (ii) allocating an array of SolElemTypes type t of sizese through x = new t[](se). Finally, we support the implicitallocation of a nested mapping of type t1 ⇒ . . . (tk ⇒ t)using x = new (t1 ⇒ t2 ⇒ . . . tk ⇒ t)().

Assignments. Figure 12 provides the translation of Solid-ity statements to Boogie statements using the function ∆.We translate require(se) (respectively assert(se)) usingassume (respectively, assert), given that these statementsterminate execution when the argument is false and we donot allow exceptions to be caught in our subset of Solidity.An assignment x = se in Solidity can either be a simple top-level assignment (of a value or address) or a deep-copy (inthe case of certain arrays). Figure 13 shows the cases wherean array assignment in Solidity is treated as assigning thereference (Ref) or performing a deep-copy (Deep) [14]. Ourtranslator currently does not handle programs that containdeep copy; this is denoted by the ⊥ when we encounter theneed for a deep copy. Translation of an array assignment∆(x[se] = y) (that does not correspond to a deep-copy) usesΓ(x[se]) to determine the array to be updated.

Functions. A function in Boogie has two additional inputparameters that correspond to the implicit parameters in aSolidity function. We add a first formal parameter with thename this that holds the value the receiver object, and thelast formal parameter with the name msg_sender that holdsthe user or contract address (msg.sender in Solidity) that in-vokes the function. The translation of internal function callsis more or less straightforward; note that the msg_senderis unchanged for an internal call. An external call first needsto perform a case-split based on the dynamic type of thereceiver object to handle dynamic dispatch due to inheri-tance; we assume a closed program where all the types areknown at compile time. Recall that the dynamic type of anobject is stored in the DType array. Once the dynamic typeDType[Γ(y)] is determined (say B), the call is dispatched tothe copy of Foo (say, FooB ) that is in scope for the dynamictype. For a given type, the Foo in scope may be defined inone of the base contracts. Since Solidity supports multipleinheritance, we traverse the list of linearized base contracts(as provided by the compiler) to find the first function withmatching signature as Foo starting from the most derived

Page 11: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Formal Specification and Verification of Smart Contracts for Azure BlockchainConference’17, July 2017, Washington, DC, USA

1 // Solidity code with nested mappings

2 // inheritance , constructor and require

3 pragma solidity ^0.4.24;

4 contract A

5 mapping (int => int[]) n;

6 constructor()

7 n[0].push(22);

8

9 function F() returns (bool)

10 return false;

11

12

13 contract B is A

14 mapping (int => int) m;

15 constructor()

16 require (n[0].length == 1);

17 m[0] = 11;

18 m[1] = 21;

19 //m[0] does not alias m[1]

20 assert (m[0] == 11);

21 //n[0][0] does not alias m[*]

22 assert (n[0][0] == 22);

23

24 function F() returns (bool)

25 return true;

26

27

28 contract C

29 A a;

30 constructor()

31 a = new B();

32 assert(a.F());

33

34

Figure 6. Solidity source code1 // global declarations

2 type Ref;

3 type ContractName;

4 var DType: [Ref]ContractName;

5 var Alloc: [Ref]bool;

6 var M_int_int: [Ref][int]int;

7 var M_int_Ref: [Ref][int]Ref;

8 var Length: [Ref]int;

9 //Allocates a new address

10 procedure Fresh(): (newRef: Ref)

11 havoc newRef; assume (!Alloc[newRef]);

12 Alloc[newRef] := true;

13

14 //Allocates an unbounded set of new addresses

15 procedure AllocUnboundedAddresses()

16 var oldAlloc: [Ref]bool;

17 oldAlloc := Alloc; havoc Alloc;

18 // ensure old allocated addresses remain

19 // allocated

20 assume (∀ i:Ref :: oldAlloc[i] ==> Alloc[i]);21

Figure 7. Boogie prelude

1 // Boogie code

2 const unique A, B, C: ContractName;

34 var n_A, m_B, a_C: [Ref]Ref;

56 // A's constructor

7 proc A_Ctor(this: Ref, msg_sender: Ref)

8 // start of initialization

9 // Make array/mapping vars distinct for n

10 call tmp := Fresh(); assume (Length[tmp] == 0);

1112 // nested array initialization

13 assume (∀ i:int :: (Length[M_int_Ref[tmp][i]] == 0));14 assume (∀ i:int :: !(Alloc[M_int_Ref[tmp][i]]));15 call AllocUnboundedAddresses();

16 assume (∀ i:int :: Alloc[M_int_Ref[tmp][i]]);17 assume (∀ i, j:int :: (i == j ||18 M_int_Ref[tmp][i] != M_int_Ref[tmp][j]));

19 assume (∀ i:int, j:int ::20 M_int_int[M_int_Ref[tmp][i]][j] == 0);

21 n_A[this] := tmp;

22 // end of initialization

2324 var l := Length[M_int_Ref[n_A[this]][0]];

25 M_int_int[M_int_Ref[n_A[this]][0]][l] := 22;

26 Length[M_int_Ref[n_A[this]][0]] := l + 1;

27

28 proc F_A(this:Ref, msg_sender: Ref) returns (r:bool)

29 r := false;

30

31 // B's constructor

32 proc B_Ctor(this: Ref, msg_sender: Ref)

33 call A_Ctor(this, msg_sender);

3435 // start of initialization

36 // Make array/mapping vars distinct for m

37 call tmp := Fresh(); assume (Length[tmp] == 0);

38 // Initialize Integer mapping m

39 assume (forall i:int :: M_int_int[tmp][i] == 0);

40 m_B[this] := tmp;

41 // end of initialization

4243 assume (Length[M_int_Ref[n_A[this]][0]] == 1);

44 M_int_int[m_B[this]][0] := 11;

45 M_int_int[m_B[this]][1] := 21;

46 assert (M_int_int[m_B[this]][0] == 11);

47 assert (M_int_int[M_int_Ref[n_A[this]][0]][0] == 22);

48

49 proc F_B(this:Ref, msg_sender: Ref) returns (r:bool)

50 r := true;

51

52 // C's constructor

53 proc C_Ctor(this: Ref, msg_sender: Ref)

54 call x := Fresh();

55 assume (DType[x] == B);

56 call B_Ctor(x, this);

57 a_C[this] := x;

58 if (DType[a_C[this]] == B) /* dyn dispatch */

59 call y := F_B(a_C[this], this); /* msg.sender update */

60 else if (DType[a_C[this]]) == A)

61 call y := F_A(a_C[this], this);

62

63 assert (y);

64

Figure 8. Translated Boogie code.

Figure 9. Example Solidity code and translated Boogie code that includes the program-independent prelude and program-specific translation.

Page 12: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Conference’17, July 2017, Washington, DC, USA Shuvendu K. Lahiri, Shuo Chen, Yuepeng Wang, and Isil Dillig

se ∈ SolExprs ::= c | x | op(se, . . . , se) | x[se] | x.lengthsst ∈ SolStmts ::= x := se | x[se] := y | sst; sst |

require(se) | assert(se) |if (se) sst else sst |while (se) do sst | x.push(se) |x = Foo( ®se) | x = y.Foo( ®se) |x = new C( ®se) | x = new t[](se) |x = new (t1 ⇒ t2 ⇒ . . . tk ⇒ t)()

Figure 10. Simple subset of Solidity language.

contract. Note that value of the sender is changed to thisto reflect that the sender is a contract. The push operationis desugared in terms of simpler statements.

Dynamic Allocation. Dynamic arrays and contract alloca-tions are handled using a helper Boogie procedure Fresh(defined in “Boogie Prelude” Fig 9) that assigns a fresh non-allocated address. The Boogie procedure Fresh uses theglobal variable Alloc to return a previously unallocatedfresh reference newRef. For dynamic array allocation of aan array of type t (new t[](se)), we initialize the Length ofthe array as well as the contents.

We treat the initialization of mappings as implicit dynamicallocations as well. We discuss the implicit allocation of anested mapping of type x = new (t1 ⇒ . . . tk ⇒ t)(). Beforediscussing the case for an arbitary k , let us discuss the casefor k ∈ [1, 2].• k= 1.Themodeling of new (t1 ⇒ t) is identical to new t[](se),except Length is not defined for a mapping.

• k = 2. For the allocation new (t1 ⇒ t2 ⇒ t)(), we needto ensure several disjointness conditions: (i) the addressof freshly allocated tmp does not alias any other previ-ously allocated address, and (ii) for any index i , (a) theaddresses of the nested arrays Γ(tmp[i]) do not alias anyother previsouly allocated address, and (b) the address ofnested arrays Γ(tmp[i]) and Γ(tmp[j]) do not alias for dis-tinct i and j. The challenge here is to ensure non-aliasingof an unbounded set of addresses. This is achieved bya call to AllocUnboundedAddresses helper procedure(part of the Boogie prelude in sub Figure 7); this pro-cedure freshly allocates an unbounded set of addresseswhile retaining the old allocated addresses. The pair ofassume statements preceding and following the call toAllocUnboundedAddresses ensure that the addressesof nested arrays do not alias with any previously allocatedaddress. The next assume states that the nested arrays forany pair of distinct indices i and j are distinct. The finalassume zero initializes the contents of the nested arrays.We informally sketch the generalization to arbitrarily deep

nested mappings new (t1 ⇒ . . . tk ⇒ t)() as provided inFigure 12. For each level j < k , we allocated an unboundedset of fresh addresses through AllocUnboundedAddresses

and install similar assumptions for ensuring non-aliasingof nested addresses at level j with any previously allocatedaddresses. Finally, for the last level k , we also zero initializethe contents.

Contract allocation of type C invokes Fresh to allocate afresh address, sets the dynamic type of the address and thencalls the constructor C_Ctor with appropriate argumentsand returns the fresh address. A call to a constructor functionC_Ctor has several steps: (i) executes the constructors ofthe base classes in the linearized order of inheritance, (ii)allocates and initializes the static state variables includingarrays and mappings, and (iii) executes the statements inC_Ctor.

Example 5.1. We briefly go over the set of initializationsthat we perform in the constructor using an example; by de-fault, values are unconstrained retaining soundness. Figure 9illustrates a simple Solidity program (sub Figure 6), and thetranslated Boogie program (sub Figures 7 and 8). The exam-ple is inspired by the PoA governance contracts (Section 2.2)that contain several nested mappings and array state andlocal variables. Ensuring initialization and non-aliasing ofnested arrays and mappings at contract allocation is cru-cial for establishing any non-trivial property. The assertionspresent in the constructor of contract B model several suchexample non-aliasing properties.

For this example, we only describe the initialization withinthe constructors; the translation of the remaining statementsfollow a straightforward application of ∆ to each Soliditystatement. Consider the constructor A_Ctor for contract A.A has a nested mapping n from integers to an array of inte-gers; we treat it as integer ⇒ integer ⇒ integer) mapping.Lines 10 to 20 in Figure 8 perform initialization related to nby following the translation of nested mapping initializationfrom Figure 12.

5.2.5 Features in progressWe currently handle a subset of the Solidity language. Mostof the unhandled features are orthogonal to the current trans-lation, and thus can be added modularly. We discuss someof these missing features in the current translation. First, weare working on designing a sound semantics for the deep-copy array assignments; we currently require simplifyingthe source code to turn such assignments into a assignmentof references. Second, we do not support low-level call state-ments using call that looks up a function using a hash ofthe signature; such calls are discouraged in favor of high-level procedure calls that we support [6]. Third, we do notsupport balance related logic for payable contracts for ex-changing ether, including send and transfer operations;interestingly, many enterprise workflow related contracts donot use payable contracts and instead use an implementationof some standard tokens (e.g. ERC20). Finally, we also cur-rently do not support modifiers, libraries, structs and inlined

Page 13: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Formal Specification and Verification of Smart Contracts for Azure BlockchainConference’17, July 2017, Washington, DC, USA

Γ(c)

c, if c is an integer, address constant literalStrToInt(c), if c is a string constant literal

Γ(x)

x, if x is a local or parametermsg_sender, if x is msg.senderx_C[this], if x is a state variable in contract C

Γ(op(se1, . . . , sek )) op(Γ(se1), . . . , Γ(sek ))

Γ(x[se])

M_t_Ref[Γ(x)][Γ(se)], if µ(SolTypeOf(se)) is t and x[se] is array typeM_t_t2[Γ(x)][Γ(se)], if µ(SolTypeOf(se)) is t and µ(SolTypeOf(x[se])) is t2

Γ(x.length) Length[Γ(x)]Γ( ®se) Γ(se0), . . . , Γ(sek−1), where k = |®e |

Figure 11. Translation of Solidity expressions to Boogie.

∆(require(se)) assume (Γ(se))∆(assert(se)) assert (Γ(se))

∆(x = se)

Γ(x) := Γ(se), if x is a scalar variable, or the assignment is by reference⊥, throw an exception for any deep copy

∆(x[se] = y) Γ(x[se]) := Γ(y)∆(sst1; sst2) ∆(sst1);∆(sst2)∆(if (e) s1 else s2) if (Γ(e)) ∆(s1) else ∆(s2)∆(while (e) do s) while (Γ(e)) do ∆(s)∆(x = Foo(®e)) call tmp := Foo(this, Γ(®e), msg_sender); Γ(x) := tmp; , // internal function call and static dispatch∆(x = y.Foo(®e)) // external call, dynamic dispatch

if (DType[Γ(y)] == A) call tmp := FooA(Γ(y), Γ(®e), this); Γ(x) := tmp; else if (DType[Γ(y)] == B) call tmp := FooB (Γ(y), Γ(®e), this); Γ(x) := tmp; . . .

else assume false;

∆(x.push(se)) ∆(x[x.length++] = se; ) //pushing a new array element∆(x = new t[](se)) //allocating a new dynamic array of type t ∈ SolElemTypes

call tmp := Fresh(); Length[tmp] := Γ(se); assume (∀i : µ(integer) :: Γ(tmp[i]) == 0); Γ(x) := tmp; ∆(x = new (t1 . . . tk ⇒ t)()) //initializing a nested mapping s.t. ti is µ(ti ) and t is µ(t)

call tmp := Fresh();Length[tmp] := 0;j := 1;while(j < k)assume (∀i1 : µ(t1), . . . , i j : µ(tj ) :: Length(Γ(tmp[i1] . . . [i j ])) == 0);assume (∀i1 : µ(t1), . . . , i j : µ(tj ) :: ¬Alloc(Γ(tmp[i1] . . . [i j ])));call AllocUnboundedAddresses();assume (∀i1 : µ(t1), . . . , i j : µ(tj ) :: Alloc(Γ(tmp[i1] . . . [i j ])));assume (∀i1 : µ(t1), . . . , i j : µ(tj ), i ′j : µ(tj ) :: (i j == i ′j ) ∨ Γ(tmp[i1] . . . [i j ]) , Γ(tmp[i1] . . . [i ′j ]));j++;assume (∀i1 : µ(t1), . . . , i j : µ(tj ) :: Γ(tmp[i1] . . . [ik ])) == 0);Γ(x) := tmp;

∆(x = new C( ®se)) //C ∈ ContractNames

call tmp := Fresh(); assume DType(tmp) == C; call C_Ctor(tmp, Γ( ®se), this); Γ(x) := tmp;

Figure 12. Translation of Solidity statements to Boogie. We do not translate statements that involve a deep copy.

Page 14: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Conference’17, July 2017, Washington, DC, USA Shuvendu K. Lahiri, Shuo Chen, Yuepeng Wang, and Isil Dillig

Figure 13. Semantics of Solidity array assignment LHS =RHS.

assembly instructions. Recall that our semantic conformancechecking in Section 4.2 used modifiers to add the runtimechecks. Our current implementation uses a slightly moreinvolved variant using a derived class to add similar checkswithout the need for modifiers. We plan to add modifiersto our translation soon as it is fairly common way to en-force preconditions including access control. We currentlydo not distinguish the different variants of integers such asunsigned integers or integers of fixed width, and model themall as unbounded integers.

6 Formal VerificationWe now describeVeriSol, a formal verifier for Solidity smartcontracts. The verifier has three main components: (i) it firstuses the Solidity to Boogie translation from Section 5 to gen-erate a Boogie program, (ii) harness construction to create aclosed program to be fed to a verifier, and (iii) use of boundedand unbounded verification techniques for Boogie programs.We focus on (ii) and (iii) in the next two subsections.

6.1 Harness ConstructionThe Boogie program derived from a Solidity program con-sists of a set of contracts, with specifications modeled asassertions in code. However, a program verifier requires aclosed program with a mainmethod to obtain a well-definedverification problem5. We describe the process of “closing”an open Boogie program as harness construction.Let us start with the case of a single contract C present

in the Solidity program. Let ∆(C) be the translated Boogieprogram.We augment ∆(C)with a main procedure in Boogieas follows:• Non-deterministically initialize the blockchain state (suchas block.blockhash, block.number, tx.origin) to anarbitrary state.

• Choose a non-deterministic address thisC .

5There are approaches to define the problem of verifying open programssuch as angelic verification [18] that we do not consider in this paper

• Invoke the translated constructor of C in Boogie file withthisC for this parameter, non-deterministic argumentsfor the remaining parameters including msg_sender.

• Repeat 0 or more times– Non-deterministically initialize the blockchain state (suchas block.blockhash, block.number, tx.origin) toan arbitrary state.

– Non-deterministically choose from one the public func-tions in C , say f .

– Invoke ∆(f ) with thisC , and non-deterministic argu-ments for the remaining parameters including msg_sender.

Although the harness construction is fairly standard forany object-oriented program, the subtlety lies in changingthe blockchain states non-deterministically before any proce-dure invocation from C . This is used to model the interleav-ing of transactions involving other contract instances ofC orother contracts between transactions involving an instancethisC of C . Since Solidity does not allow a transaction todirectly mutate a state variable of a contract, we do not needto modify the state variables in between two transactionsinvolving the instance thisC . Finally, the ability to choose amsg_sender non-deterministically for every call allows usto model transactions submitted by different users. Together,it is not difficult to see that the traces of main contain theeffect of all user-submitted transactions that involve oneinstance of C . Hence, if we can prove that every executionof main satisfies all the assertions present in C , then we canestablish that C does not fail any assertion at runtime.We should observe that the harness soundly captures all

transactions even for cases of multiple contracts with a singletop-level contract that performs nested contract creationusing new. However the harness is no longer sound for casesof two or more interacting contract instances, each of whichmay be independently updated by user transactions. In suchcases, we first require the user to create a Solidity metacontract with state variables for the different instances, anda union of the functions from the different contracts, beforeapplying the above harness construction.

6.2 Boogie-based Verifiers

Figure 14. VeriSol tool flow.

Page 15: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Formal Specification and Verification of Smart Contracts for Azure BlockchainConference’17, July 2017, Washington, DC, USA

Figure 14 shows the high-level block diagram of VeriSol.Given a Boogie program ∆(C) with a main method, we caneither use the verifier to find a counterexample or look fora proof. A counterexample corresponds to a sequence oftransactions τ1, . . . ,τk where τ1 creates an instance of thetop-level contract in ∆(C) and τk is the first transaction in thesequence that reverts due to a violation of some assertion inC . On the other hand, a proof corresponds to the guaranteethat no sequence of transactions for the top-level contractin ∆(C) can result in an assertion failure at runtime.

Unbounded Verification. Observe that the problem of ver-ifying the correctness of the translated Boogie program isundecidable due to the presence of unbounded integers anda top-level unbounded loop for the harness. Hence, we canonly resort to sound but necessarily incomplete invariantgeneration schemes to prove the absence of runtime errors.We currently use the Houdini algorithm [20] and its im-plementation in Boogie [25] for constructing an inductiveinvariant over a set of candidate predicates. The algorithmconjectures the conjunction of all candidate predicates as aninductive invariant and progressively weakens it based onfailure to prove a candidate predicate inductive. The algo-rithm converges fairly fast on large examples but relies onstarting with the a superset of necessary predicates. VeriSolfirst tries Houdini to look for a proof; it only reports a suc-cessful proof to the user. Note that an inductive invariant forthe top-level loop in the harness corresponds to a moduleinvariant — a fact that is established by the constructor andpreserved by public functions of the module.

Transaction-bounded Verification. If Houdini fails tofind a proof, VeriSol uses a property-directed bounded ver-ifier Corral [26] to look for a trace in the main programleading to an assertion violation. Corral uses a combinationof abstraction refinement techniques and stratified inliningof procedure calls to look for a counterexample in a scalablemanner. Corral requires a bound k on unrolling of loops andrecursive calls — this corresponds to a k transaction-boundedanalysis of the contract C due to the top-level loop in theharness. Corral either successfully finds a counterexample orverifies the lack of any counterexample with k transactions.VeriSol also comes with a defect viewer that allows a userto view the failing trace by stepping through the Soliditycode, including values of various variables along the trace.

7 ResultsIn this Section, we detail the use of VeriSol on smart con-tracts present in the Azure Blockchain content and sampleson github [7]6. In Section 7.1, we describe the applicationto 8 Workbench sample contracts to check semantic confor-mance with respect to their state machine based WorkbenchApplication Configuration (Section 4). Next, in Section 7.2

6As of commit 1571029 on August 7th, 2018.

Example Description of workflowAssetTransfer Selling high-value assetsBasicProvenance Simple record of ownershipBazaarItemListing Multiple workflow scenario for

selling itemsDigitalLocker Sharing digitally locked filesHelloBlockchain Request and response (Figure 1)RefrigSupport Provenance scenario with IoT

monitoringRoomThermostat Thermostat installation and useSimpleMarketplace Owner and buyer transaction

Table 1. Description of Workbench Samples.

we describe the application to check safety properties forthe contracts for PoA governance. We describe previouslyunknown bugs that have been found, confirmed and fixed bythe authors of these contracts, and also report on unboundedverification for Workbench samples with respect to theirspecifications. All experiments were run on a Intel Xeon3.6HGz machine with 32 GB RAM running Windows 10.

7.1 Workbench SamplesTable 1 summarizes the eight sample smart contracts that areoffered as part of the Azure Blockchain Workbench. We havealready described one of the samples HelloBlockchainin detail as our running example in Section 2. The remain-ing examples similarly demonstrate some customer scenarioworkflow. For example, AssetTransfer is a workflow forselling a high-value asset such as a house that involves sev-eral parties such as a seller, buyers, inspector, appraisersetc. DigitalLocker illustrates a workflow for sharing adigitally locked file. RefrigSupport demonstrates the in-tegration of events from IoT temperature sensor devices tomonitor if a refrigerated shipment has not gone bad. Foreach of these samples, we use a utility tool AppEnforcerto instrument the Solidity code with checks for semanticconformance similar to that described in Section 4.2. Theresulting Solidity program is fed to VeriSol to verify theassertions.

7.1.1 Bugs FoundWe report on three bugs that VeriSol found in the sample,related to incorrect initial state and state transition.

AssetTransfer. Figure 15 provides a pictoral descriptionof the the access control and state transitions for the contractAssetTransfer 7. It is a fairly non-trivial state transitionsystem where the actions are guarded by membership ofmsg.sender within one of the roles or instance role vari-ables. VeriSol found a bug where the transition from the

7https://github.com/Azure-Samples/blockchain/tree/master/blockchain-workbench/application-and-smart-contract-samples/asset-transfer

Page 16: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Conference’17, July 2017, Washington, DC, USA Shuvendu K. Lahiri, Shuo Chen, Yuepeng Wang, and Isil Dillig

Figure 15. AssetTransfer access control and state transition specification.

1 function Accept() public

2

3 if (msg.sender != InstanceBuyer &&

4 msg.sender != InstanceOwner)

5 revert();

6

7 ...

89 if (msg.sender == InstanceBuyer)

10 ...

11

12 else

13 // msg.sender has to be InstanceOwner

14 // from the revert earlier

15 if (State == StateType.NotionalAcceptance)

16 State = StateType.SellerAccepted;

17

18 else if (State == StateType.BuyerAccepted)

19 // BUG: Should be StateType.SellerAccepted

20 State = StateType.Accepted;

21

22

23 ...

24

Figure 16. Function Accept of AssetTransfer.

state BuyerAccepted to SellerAccepted was incorrectly

implemented in the accompanying smart contract. The spec-ification allows a transition between the two states wheninvoking the function Acceptwhen msg.sender equals theinstance role variable InstanceOwner (abbreviated as IO inthe diagram). However, the implementation of the functionAccept in Solidity transitions to the state Accepted insteadunder the same transition.This is an example of a fairly deep bug, as it requires

at least 6 transactions to reach the state BuyerAcceptedfrom the initial state, each executing a function with sev-eral lines of Solidity code. We can speculate that the authorof this sample either did not have tests that exercised suchdeep transactions, or test oracles to observe the incorrecttransition. The defect trace is an interprocedural trace ter-minating with Accept. The trace within Accept consists oflines 3, 9, 15, 18 and 20. The transaction bounded verificationusing Corral found this bug within 5.96 seconds. In theprocess, it inlined 954 procedures indicating the non-trivialsearch required to discover the defect.

DigitalLocker. VeriSol found a bug related to incorrectinitial state of the smart contract. According to the specifi-cation, the start state of the contract should be Requested,however the constructor terminates in DocumentReview.

Page 17: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Formal Specification and Verification of Smart Contracts for Azure BlockchainConference’17, July 2017, Washington, DC, USA

This was confirmed as a true bug and was introduced whileporting the smart contract and an older code, for which theinitial state was indeed DocumentReview; the configurationwas updated to the new initial state, however the smart con-tract initial state was not refreshed.

BazaarItemListing. We also found a similar bug wherethe initial state of a nested contract was not set accordingto the one specified in the JSON specification. This is aninteresting contract that consists of two separate contractsBazaarItemListing and ItemListing, where a functionin the former creates an instance of the latter contract usingdynamic allocation new ItemListing(...). The state ofthe newly created ItemListing contract was set using alater function call. The source of the bug was related to thesemantics of the Workbench JSON configuration specifica-tion for the case of nested contract creation. Our bug pointedthe developers to the ambiguity of the specification and thesemantics was resolved in favor of fixing the bug.

All the three bugs have been confirmed by the developersof Azure Blockchain content and samples, and have beenfixed in their internal repositories and their internal testshave been updated; some of the bugs (e.g. BazaarItemListing)have been fixed for the external code on github, and otherswill be updated in one of their future releases8.

7.1.2 Unbounded VerificationAlthough the Corral based transaction-bounded verifica-tion allows us to explore fairly deep into the state space ofthe contracts, it does not offer any guarantees about arbi-trarily large number of transactions. Besides, for a correctprogram, the verification takes longer as the transaction-bound is increased. For example, for the AssetTransfercontract, verifying the fixed version for bounds 6, 8, 10, 12take respectively 5, 29, 79, 184 seconds.

Once we fix the bugs in the sample contracts, we use theHoudini-based unbounded verification for the contracts. Re-call that Houdini requires the user to specify a candidateset of predicates at different program points (procedure en-try and exit, and loop heads). A good choice of predicatesrelies on the property under consideration. For the semanticconformance checking, we observe that most invariants re-late to the values of the instance role variables. For example,the smart contract code for Accept in Figure 16 relies oncomparisons of msg.senderwith various instance role vari-ables such as InstanceOwner and InstanceBuyer. Basedon this observation, we generate a set of candidate predicatesfor the top-level loop in the harness main generated for acontract. Since the only variables in scope at the loop headare the state variables, we consider all possible aliasing andnon-aliasing predicates between state variables of instancerole type. That is, if x and y are state variables of some role

8As of December 12, 2018

type, we generate the following set of candidate predicatesx == y, x != y, x == 0x0, x != 0x0, y == 0x0, y != 0x0 .

With these candidate predicates, Houdini infers safe in-ductive invariant that is (i) established by the constructor,and (ii) preserved by the execution of any public function ofthe contract, and (iii) verifies all the assertions present in theBoogie programs. For all the sample contracts, the invariantinference takes in the order of few seconds. For the case ofthe AssetTransfer smart contract, we infer the followingsafe inductive invariant:

(this.InstanceOwner , 0x0) ∧(this.InstanceOwner , this.InstanceBuyer)

7.2 PoA Governance ContractsIn this section, we describe the application of VeriSol tothe PoA Governance contracts that we described earlier inSection 2.2. For these contracts, we check the correctnessof assertions already present in the contracts, as well asadditional safety specifications.We have applied the boundedverification to these properties and report several injectedand previously unknown bugs.Recall that the PoA governance smart contracts imple-

ment the Parity ValidatorSet interface for managing PoA net-works. The ValidatorSet has the following interface, wheregetValidators returns the current set of validators. Theevent Initiatechange is issued to signal a desire to changethe validator set, and a call to finalizeChange to persistthe change.

contract ValidatorSet

event InitiateChange(bytes32 indexed _parent_hash ,

address[] _new_set);

function getValidators() constant

returns (address[] _validators);

function finalizeChange();

Figure 17. Parity ValidatorSet interface.

In Figure 18, we describe the properties we check for thesecontracts. Pr1 states that the system should always have atleast one admin present; the network is initialized with asingle admin at bootstrapping. In case this invariant doesnot hold, the entire network will enter into a livelock statewhere any subsequent transaction will revert. Pr2 ensuresthat no validator becomes orphaned; if an admin is votedout of the system, then all the validators that belong to theadmin should also be removed from the list of validators. Thedeveloper of the contract informed us that this was one ofthe known bug that existed in a prior version of the contractthat had since been fixed. Pr3 ensures that a validator doesnot belong to multiple admins; it can lead to unexpectedconsequences for the governance protocol. Next, recall thatthe AdminSet is a contract that exposes a set interface toperform constant time operations such as lookup; since So-lidity does not permit enumerating all the keys in a mapping,

Page 18: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Conference’17, July 2017, Washington, DC, USA Shuvendu K. Lahiri, Shuo Chen, Yuepeng Wang, and Isil Dillig

the set is implemented as a combination of an array of mem-bers addressList and a Boolean mapping inSet to mapthe members to true. Pr4 checks the coupling between thesetwo data structures — (i) addressList has no repeated ele-ments, (ii) inSet[a] is true if an only if there is an index jsuch that addressList[j] == a. For the purpose of verifica-tion, we introduced a ghost variable that maintains the indexj into addressList for an address a. Finally, Pr5 checksthat a call to a helper method deleteArrayElement is onlyinvoked with an element present in the array; this is oneof the assertions present in the original contract. Most ofthe properties except Pr4 require reasoning over all the con-tracts; Pr4 requires reasoning about AdminSet and Admincontracts only, as it checks the set abstraction exposed bythe AdminSet contract.

Property DescriptionPr1 There is at least one elected adminPr2 Every validator belongs to an elected adminPr3 No validator belongs to two elected adminsPr4 AdminSet implements a setPr5 deleteArrayElement deletes an element

Figure 18. Properties for PoA governance contracts.

7.2.1 Bugs FoundWe now describe some of bugs that we found using thebounded verifier:

Pr5. We describe a sequence of transactions that results inviolation of this property. The user issues a transaction tocreate an instance of AdminValidatorSet. Let x be oneof the validators that are added for the first admin (sayadmin0) at the bootstrapping time. The admin0 issues atransaction to remove the validator x from its list of valida-tors that results in a call to emit InitiateChange eventafter removing x (using deleteArrayElement) from a in-ternal validator set called pendingValidatorSet; a callto finalizeChange would persist this change. However,if admin0 issues another transaction to remove x , then thecall to deleteArrayElement fails the Pr5 invariant, since xhas already been removed from the pendingValidatorSet.Although this particular defect results in reverting certain(illegal) transactions, the scenario can be extrapolated toother buggy scenarios where an admin fails to add validatorsto the network. The bug resulted from a missing modifierthat disallows two consecutive calls to InitiateChangewithout an call to finalizeChange.

Assert as require. VeriSol was able to find counterexam-ples to several Solidity assert in the code that were actuallymeant to check for certain preconditions. Although bothrequire and assert failures revert an execution, Solidity

recommends using assert only for violations of internalinvariants that are not expected to fail at runtime. Most ofthem could have been spotted during a code review as theywere present in the first few lines of a public function; mostof them checked for access control or avoid adding a du-plicate validator or admin already present in the system byperforming a lookup in a mapping. However, there were afew asserts that were deeply nested inside private methodsand relied on finding an element in an array (e.g. finding if avalidator that is a candidate for removal is present in an arrayin an internal method removeValidatorsInternal).We note that these previously unknown defects in PoA

contracts only lead to safety violations, and as far as wecould see, do not lead to security issues that can be exploitedby a malicious user.

Injected bugs In addition to the bugs above, we were ableto use VeriSol to find bugs that existed in prior versions ofthe contracts. For example, we found a counterexample toPr2 when the code to cleanup validators after removing anadmin was commented out. Similarly, when we commentedout a precondition that ensured that the number of validatorsshould never fall below 2, we were able to create a sequenceof transactions where admin0 was able to vote itself outfrom the system, resulting in a livelock.

The unknown bugs have been confirmed by the developerand have been fixed in the latest binary releases; the code ongithub will be updated in a future release. The complexity ofseveral nested mappings, arrays, and inheritance requiredprecise initialization of arrays and nested mappings to elimi-nate spurious aliasing between multiple mappings, or arraysat two different indices within a nested mapping. Unlike theWorkbench samples, we were only able to scale the boundedverification for the fixed contracts up to a transaction-depthof 4 (13 hours), with depth 3 taking 11 seconds. The hugedifference in time can be partially attributed to the differencein the number of procedures inlined by Corral (77 for depth3 vs 831 for depth 4). For property Pr4 that only involvedthe AdminSet, we were able to explore transaction depths 5,6, 7 within 14, 50, 242 seconds respectively.

8 Related WorkIn this work, we formalized a specification for smart con-tracts and described a new formal verifier VeriSol for verify-ing Solidity smart contracts. In this section, we discuss priorworks on ensuring the safety and security of smart contracts.The set of techniques for design and analysis of smart con-tracts can be roughly categorized into the following groups:(i) static analysis approaches for finding vulnerable patterns,(ii) formal verification based approaches, and (iii) runtimechecking, and (iv) high-level languages. In addition, therehas been work on formalizing the semantics of EVM in a for-mal language such as the K Framework [23]. Finally, there

Page 19: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Formal Specification and Verification of Smart Contracts for Azure BlockchainConference’17, July 2017, Washington, DC, USA

are several works that discuss a survey and taxonomy ofvulnerabilities in smart contracts [15, 27, 30].

The set of static analysis tools are based on a choice ofdata-flow analysis or symbolic execution to find variants ofknown vulnerable patterns. Such patterns include the use ofreentrancy, transaction ordering dependencies, sending etherto unconstrained addresses that may lead to lost ether, use ofblock time-stamps, mishandled exceptions, calling suicideon an unconstrained address, etc. Tools based on symbolicexecution include Oyente [27], MAIAN [30], Manticore [11],and Mythril++ [12]. On the other hand, several data-flowbased tools also exists such as Securify [31] and Slither [13].Finally, the MadMax tool [21] performs static analysis to findvulnerabilities related to out-of-gas exceptions. These toolsdo not support high-level state machine based specificationsor formal specifications, and mostly find instances of knownvulnerable patterns (Securify allows users to write their ownpatterns) and do not provide any soundness or complete-ness guarantees. These tools cannot be used to analyze theconformance problem for the Workbench contracts, nor candetect the data structure consistency properties such as Pr4for PoA contracts. On the other hand, VeriSol does not rea-son about gas consumption since it analyzes Solidity code,and also needs the vulnerabilities to be expressed as formalspecifications.Approaches based on program verifiers have been pro-

posed such as based on F* [17] and Zeus [24]. These ap-proaches translate Solidity to the formal verification lan-guages of F* and LLVM respectively. Then verifiers basedon F* and LLVM-based constrained horn clause solvers re-spectively are applied to verify the translated program. Zeusalso provides a policy language to allow specifying safetyand fairness policies. Although the F* based approach isfairly expressive, the tool only covers a small subset of So-lidity without loops and requires substantial user guidanceto discharge proofs of user-specified assertions. The designof Zeus shares similarity with VeriSol in translating to anintermediate language and using SMT based solvers to dis-charge the verification problem. However, there are severaldifferences in the capabilities of the two works. First, theZeus policy language does not seem to express state machinebased specification that we formalize forWorkbench. Second,Zeus only provides an informal description of the transla-tion to LLVM, unlike our formal treatment of the translationto Boogie. The memory model in the presence of nestedarrays and mappings is not defined; the meaning of arrayassignments depends on the context (see Figure 13) but suchdistinction is not made in the translation. Unfortunately, wewere unable to obtain a copy of Zeus to try on our examples,making it difficult for us to perform a qualitative treatmenton our examples.In addition to the static analyzers and verifiers, there are

approaches for enforcing safe reentrancy patterns at run-time by borrowing ideas from linearizability [22]. Finally,

FSolidM [28] provides an approach to specify a smart con-tract using a finite state machine with actions written inSolidity. Although, there is similarity in the state machinemodel with theWorkbench specification, there is no mentionof access control and (as far as we can tell) the actions do nothave nested procedure calls or loops. Finally, the tool doesnot provide any static or dynamic verification support.

9 ConclusionIn this work, we described one of the first uses of automatedformal verification for smart contracts in an industrial setting.We provided formal semantics to the Workbench applicationconfiguration, and performed automatic program instrumen-tation to enforce such specifications. We described a newformal verification tool VeriSol using the Boogie tool chain,and illustrate its application towards non-trivial smart con-tracts verification and bug-finding. For the immediate future,we are working on adding more features of Solidity languagethat are used in common enterprise workflows, and explorehorn-clause based invariant inference. We also plan to applyVeriSol for verifying assertions for Solidity smart contractspresent in the Ethereum eco-system.

AcknowledgmentsWe are deeply grateful to members of the Azure Blockchainteam at Microsoft for their feedback on our work. In par-ticular, we thank Shaz Qadeer for suggesting the use of for-mal verification for smart contracts in Azure Blockchainoffering and introducing us to the Workbench configurationlanguage. We thank Cody Born for explaining the workingof PoA protocol and desired properties of the PoA offeringin Ethereum on Azure. We also thank Immad Naseer fordiscussions around the Workbench specification language.Finally, all opinions expressed in this work are solely thoseof the authors.

References[1] 2015. Hyperledger Fabric. https://www.hyperledger.org/projects/

fabric.[2] 2016. Explaining the DAO exploit for beginners in So-

lidity. https://medium.com/\spacefactor\@mMyPaoG/explaining-the-dao-exploit-for-beginners-in-solidity-80ee84f0d470.

[3] 2016. Solidity: Function Modifiers. https://solidity.readthedocs.io/en/v0.4.24/structure-of-a-contract.html#function-modifiers.

[4] 2017. Azure Blockchain. https://azure.microsoft.com/en-us/solutions/blockchain/.

[5] 2017. Parity: The bug that put $169m of Ethereum on ice? Yeah, it wason the todo list for months. https://www.theregister.co.uk/2017/11/16/parity_flaw_not_fixed.

[6] 2017. Warning: The use of low level "call" should be avoided wheneverpossible. https://ethereum.stackexchange.com/questions/25068/warning-the-use-of-low-level-call-should-be-avoided-whenever-possible.

[7] 2018. Applications and Smart Contract Samples for Work-bench. https://github.com/Azure-Samples/blockchain/tree/master/blockchain-workbench/application-and-smart-contract-samples.

Page 20: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Conference’17, July 2017, Washington, DC, USA Shuvendu K. Lahiri, Shuo Chen, Yuepeng Wang, and Isil Dillig

[8] 2018. Azure Blockchain Content and Samples. https://github.com/Azure-Samples/blockchain.

[9] 2018. Ethereum on Azure. https://github.com/Azure-Samples/blockchain/tree/master/ledger/template/ethereum-on-azure.

[10] 2018. Ethereum Proof-of-Authority on Azure. https://azure.microsoft.com/en-us/blog/ethereum-proof-of-authority-on-azure/.

[11] 2018. Manticore. https://github.com/trailofbits/manticore.[12] 2018. Mythril Classic: Security analysis tool for Ethereum smart con-

tracts. https://mythril.ai.[13] 2018. Slither, the Solidity source analyzer. https://github.com/

trailofbits/slither.[14] 2018. Solidity: Complications for Arrays and Structs. https://solidity.

readthedocs.io/en/v0.4.24/control-structures.html.[15] Nicola Atzei, Massimo Bartoletti, and Tiziana Cimoli. 2017. A Survey

of Attacks on Ethereum Smart Contracts (SoK). In Principles of Securityand Trust - 6th International Conference, POST , Uppsala, Sweden, April22-29, 2017, Proceedings. 164–186.

[16] Michael Barnett, Bor-Yuh Evan Chang, Robert DeLine, Bart Jacobs,and K. Rustan M. Leino. 2005. Boogie: A Modular Reusable Verifierfor Object-Oriented Programs. In Formal Methods for Components andObjects, 4th International Symposium, FMCO 2005, Amsterdam, TheNetherlands, November 1-4, 2005, Revised Lectures. 364–387.

[17] Karthikeyan Bhargavan, Antoine Delignat-Lavaud, Cédric Fournet,Anitha Gollamudi, Georges Gonthier, Nadim Kobeissi, Natalia Kula-tova, Aseem Rastogi, Thomas Sibut-Pinote, Nikhil Swamy, and Santi-ago Zanella Béguelin. 2016. Formal Verification of Smart Contracts:Short Paper. In Proceedings of the 2016 ACMWorkshop on ProgrammingLanguages and Analysis for Security, PLAS@CCS 2016, Vienna, Austria,October 24, 2016. 91–96.

[18] Ankush Das, Shuvendu K. Lahiri, Akash Lal, and Yi Li. 2015. An-gelic Verification: Precise Verification Modulo Unknowns. In ComputerAided Verification - 27th International Conference, CAV 2015, San Fran-cisco, CA, USA, July 18-24, 2015, Proceedings, Part I, Vol. 9206. Springer,324–342.

[19] Leonardo De Moura and Nikolaj Bjørner. 2008. Z3: An efficient SMTsolver. In Tools and Algorithms for the Construction and Analysis ofSystems. Springer, 337–340.

[20] Cormac Flanagan and K Rustan M Leino. 2001. Houdini, an annotationassistant for ESC/Java. In International Symposium of Formal MethodsEurope. Springer, 500–517.

[21] Neville Grech, Michael Kong, Anton Jurisevic, Lexi Brent, BernhardScholz, and Yannis Smaragdakis. 2018. MadMax: surviving out-of-gasconditions in Ethereum smart contracts. PACMPL 2, OOPSLA (2018),116:1–116:27.

[22] Shelly Grossman, Ittai Abraham, Guy Golan-Gueta, Yan Michalevsky,Noam Rinetzky, Mooly Sagiv, and Yoni Zohar. 2018. Online detectionof effectively callback free objects with applications to smart contracts.PACMPL 2, POPL (2018), 48:1–48:28.

[23] Everett Hildenbrandt, Manasvi Saxena, Nishant Rodrigues, XiaoranZhu, Philip Daian, Dwight Guth, Brandon M. Moore, Daejun Park, YiZhang, Andrei Stefanescu, and Grigore Rosu. 2018. KEVM: A Com-plete Formal Semantics of the Ethereum Virtual Machine. In 31st IEEEComputer Security Foundations Symposium, CSF 2018, Oxford, UnitedKingdom, July 9-12, 2018. 204–217.

[24] Sukrit Kalra, Seep Goel, Mohan Dhawan, and Subodh Sharma. 2018.ZEUS: Analyzing Safety of Smart Contracts. In 25th Annual Networkand Distributed System Security Symposium, NDSS 2018, San Diego,California, USA, February 18-21, 2018.

[25] Shuvendu K. Lahiri, Shaz Qadeer, Juan P. Galeotti, Jan W. Voung,and Thomas Wies. 2009. Intra-module Inference. In Computer AidedVerification, 21st International Conference, CAV 2009, Grenoble, France,June 26 - July 2, 2009. Proceedings. 493–508.

[26] Akash Lal, Shaz Qadeer, and Shuvendu K. Lahiri. 2012. A Solver forReachability Modulo Theories. In Computer Aided Verification - 24th

International Conference, CAV 2012, Berkeley, CA, USA, July 7-13, 2012Proceedings, Vol. 7358. Springer, 427–443.

[27] Loi Luu, Duc-Hiep Chu, Hrishi Olickel, Prateek Saxena, and AquinasHobor. 2016. Making Smart Contracts Smarter. In Proceedings of the2016 ACM SIGSAC Conference on Computer and Communications Secu-rity, Vienna, Austria, October 24-28, 2016. 254–269.

[28] Anastasia Mavridou and Aron Laszka. 2018. Tool Demonstration:FSolidM for Designing Secure Ethereum Smart Contracts. In Principlesof Security and Trust - 7th International Conference, POST 2018, Held asPart of the European Joint Conferences on Theory and Practice of Soft-ware, ETAPS 2018, Thessaloniki, Greece, April 14-20, 2018, Proceedings.270–277.

[29] Microsoft. 2017. The Confidential Consortium Blockchain Frame-work. https://github.com/Azure/coco-framework/blob/master/docs/Coco%20Framework%20whitepaper.pdf.

[30] Ivica Nikolic, Aashish Kolluri, Ilya Sergey, Prateek Saxena, andAquinasHobor. 2018. Finding The Greedy, Prodigal, and Suicidal Contracts atScale. In Proceedings of the 34th Annual Computer Security ApplicationsConference, ACSAC 2018, San Juan, PR, USA, December 03-07, 2018.653–663.

[31] Petar Tsankov, Andrei Marian Dan, Dana Drachsler-Cohen, ArthurGervais, Florian Bünzli, and Martin T. Vechev. 2018. Securify: PracticalSecurity Analysis of Smart Contracts. In Proceedings of the 2018 ACMSIGSAC Conference on Computer and Communications Security, CCS2018, Toronto, ON, Canada, October 15-19, 2018. 67–82.

A Runtime Checking for SemanticConformance

We briefly discuss some choices for realizing runtime checksin the presence of a non-deterministic function such asNonDetFunc. We do this by essentially eliminating (quanti-fying out) NonDetFunc from any expression it appears in.Consider a predicate ϕ containing a call to NonDetFunc thatappears in either require or assert as part of the instru-mentation described above; further let ϕ contains k calls toNonDetFunc. We have two such options:

1. Replace ϕ with ϕ0 ∧ . . .ϕ2k−1, where ϕi replaces thevector of calls to NonDetFuncwith the Boolean vectorfor the integer i . For example, if there are two calls toNonDetFunc inϕ, then we getϕ0 by replacing the callswith false, false; similarly, we get ϕ2 by replacingcalls with true, false respectively.

2. Convert ϕ to a negation-normal form ϕ where a call toNonDetFunc either appears negatively or positively.Next, we replace any negative (respectively, positive)occurrence of the call with false (respectively, true).

The first check is sound but overly conservative as it willfail many require that mention a global role. For runtimechecking it is undesirable to revert transactions conserva-tively in the absence of information about global roles. Sinceglobal roles are already being checked by Workbench, wewould like to revert a transaction only when we are guar-anteed that it fails the specification. In contrast, the secondcheck weakens the predicate ϕ and therefore a failure will bea true violation of the intended specification we outlined inSection 4.1. In essence, the second transformation replaces

Page 21: Formal Specification and Verification of Smart Contracts ... · specifications and verifications to smart contracts: •Smart contract vulnerabilities. Unlike traditional pro-gramswritteninhigh-levelprogramminglanguages,smart

Formal Specification and Verification of Smart Contracts for Azure BlockchainConference’17, July 2017, Washington, DC, USA

calls to the non-deterministic function in require (respec-tively, assert) with true (respectively, false). We thereforeuse the second transformation of ϕ for installing runtimechecks.Figure 19 describes the actual checks that are inserted

for runtime enforcement using the second transformationdescribed above. We show the original expressions in com-ments. As noted, the (positive) occurrence of NonDetFuncin require statements are replaced with true making therequire in constructor_checker true. The (negative) oc-currence of NonDetFunc in SendResponse_checker is re-placed with false making the assert true. Therefore, forthis example, we only check two assertions related to initialstate and state transition when invoking SendRequest.

// Checker modifiers

modifier constructor_checker()

// require (msg.sender != tx.origin ||

// NonDetFunc());

require (true);

_;

assert (State == StateType.Request);

modifier SendRequest_checker()

StateType oldState = State;

address oldRequestor = Requestor;

_;

assert ((msg.sender == oldRequestor &&

oldState == StateType.Respond)

==> State == StateType.Request);

modifier SendResponse_checker()

StateType oldState = State;

_;

//assert ((NonDetFunc() &&

// oldState == StateType.Request)

// ==> State == StateType.Respond);

assert (true);

Figure 19. Modifier definitions for instrumented Hel-loBlockchain application for runtime checking.