This paper was converted on www.awesomepapers.org from LaTeX by an anonymous user.
Want to know more? Visit the Converter page.

11institutetext: University of Waterloo, Canada 22institutetext: MPI-SWS, Germany 33institutetext: SRI International, USA 44institutetext: ConsenSys, Germany

Compositional Verification of Smart Contracts Through Communication Abstraction (Extended)

Scott Wesley 11    Maria Christakis 22    Jorge A. Navas 33    Richard Trefler 11   
Valentin Wüstholz
44
   Arie Gurfinkel 11
Abstract

Solidity smart contracts are programs that manage up to 21602^{160} users on a blockchain. Verifying a smart contract relative to all users is intractable due to state explosion. Existing solutions either restrict the number of users to under-approximate behaviour, or rely on manual proofs. In this paper, we present local bundles that reduce contracts with arbitrarily many users to sequential programs with a few representative users. Each representative user abstracts concrete users that are locally symmetric to each other relative to the contract and the property. Our abstraction is semi-automated. The representatives depend on communication patterns, and are computed via static analysis. A summary for the behaviour of each representative is provided manually, but a default summary is often sufficient. Once obtained, a local bundle is amenable to sequential static analysis. We show that local bundles are relatively complete for parameterized safety verification, under moderate assumptions. We implement local bundle abstraction in SmartACE, and show order-of-magnitude speedups compared to a state-of-the-art verifier.

1 Introduction

Solidity smart contracts are distributed programs that facilitate information flow between users. Users alternate and execute predefined transactions, that each terminate within a predetermined number of steps. Each user (and contract) is assigned a unique, 160160-bit address, that is used by the smart contract to map the user to that user’s data. In theory, smart contracts are finite-state systems with 21602^{160} users. However, in practice, the state space of a smart contract is huge—with at least 221602^{2^{160}} states to accommodate all users and their data (conservatively counting one bit per user). In this paper, we consider the challenge of automatically verifying Solidity smart contracts that rely on user data.

A naive solution for smart contract verification is to verify the finite-state system directly. However, verifying systems with at least 221602^{2^{160}} states is intractable. The naive solution fails because the state space is exponential in the number of users. Instead, we infer correctness from a small number of representative users to ameliorate state explosion. To restrict a contract to fewer users, we first generalize to a family of finite-state systems parameterized by the number of users. In this way, smart contract verification is reduced to parameterized verification.

1contract Auction {
2 mapping(address => uint) bids; ÂÂ
3 address manager; uint leadingBid; bool stopped; ÂÂ
4 °uint _sum;°
5
6 constructor(address mgr) public { manager = mgr; }ÂÂ
7
8 function bid(uint amount) public { ÂÂ
9 require(msg.sender != manager); ÂÂ
10 require(amount > leadingBid); ÂÂ
11 require(!stopped);
12 °_sum = _sum + amount - bids[msg.sender];°
13 bids[msg.sender] = amount;
14 leadingBid = amount;
15 }
16
17 function withdraw() public { ÂÂ
18 require(msg.sender != manager); ÂÂ
19 require(bids[msg.sender] != leadingBid); ÂÂ
20 require(!stopped);
21 °_sum = _sum + 0 - bids[msg.sender];°
22 bids[msg.sender] = 0; ÂÂ
23 }
24
25 function stop() public { ÂÂ
26 require(msg.sender == manager); ÂÂ
27 stopped = true;
28 }
29}
Figure 1: A smart contract that implements a simple auction.
1Auction _a = new Auction(address(2));
2_a.address = address(1);
3
4while (true) {
5 // Applies an interference invariant.
6 °uint bid = *;° ÂÂ
7 °uint maxBid = _a.leadingBid;°
8 °require(bid <= maxBid);°
9 °require(bid == maxBid || bid + maxBid <= _a.sum);°
10 °_a.bids[address(3)] = bid;° ÂÂ
11 // Selects a sender.
12 msg.sender = *;
13 require(msg.sender > address(1)); ÂÂ
14 require(msg.sender < address(5));
15 °require(msg.sender < address(4));° ÂÂ
16 // Selects a call.
17 if (*) _a.bid(*);
18 else if (*) _a.withdraw();
19 else if (*) _a.stop();
20}
Figure 2: A harness to verify Prop. 1 (ignore the highlighted lines) and Prop. 2.

For example, consider {Auction} in \cref{Fig:Auction} (for now, ignore the highlighted lines). In \mbox{\code{Auction},} each user starts with a bid of $0$. Users alternate, and submit increasingly larger bids, until a designated manager stops the auction. While the auction is not stopped, a non-leading user may withdraw their bid\footnote{For simplicity of presentation, we do not use Ether, Ethereum’snativecurrency.}.\code{Auction}satisfies\prop{1}:‘‘\emph{Once\mbox{\code{stop()}}iscalled,allbidsareimmutable}.’\prop{1}␣␣␣␣␣␣␣␣issatisfiedsince\mbox{\code{stop()}}sets\code{stopped}totrue,nofunction␣␣␣␣␣␣␣␣sets\code{stopped}tofalse,andwhile\code{stopped}istrueneither␣␣\mbox{\code{bid()}}nor\mbox{\code{withdraw()}}isenabled.Formally,\prop{1}isinitiallytrue,andremainstruedueto\prop{1b}:‘‘\emph{Once␣␣␣␣␣␣\mbox{\code{stop()}}iscalled,\code{stopped}remainstrue}.’\prop{1}issaid␣␣␣␣␣␣␣␣tobeinductiverelativetoits\emph{inductivestrengthening}\prop{1b}.A␣␣␣␣␣\emph{SoftwareModelChecker(SMC)}canestablish\prop{1}byanexhaustive␣␣␣␣␣searchforitsinductivestrengthening.However,thisrequiresaboundonthe␣␣␣numberofaddresses,sinceasearchwithall$2^{160}$addressesisintractable.␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣Aboundofatleastfouraddressesisnecessarytorepresentthezero-account␣␣␣(i.e.,anulluserthatcannotsendtransactions),thesmartcontractaccount,␣␣themanager,andanarbitrarysender.However,oncethearbitrarysendersubmits␣␣␣␣␣␣␣␣abid,thesenderisnowtheleadingbidder,andcannotwithdrawitsbid.To␣␣␣␣enable\mbox{\code{withdraw()},}afifthuserisrequired.Itfollowsbyapplying␣␣␣␣␣␣␣theresultsof~\cite{KaiserKroening2010},thataboundoffiveaddressesisalso␣␣␣␣␣␣␣␣sufficient,sinceusersdonotreadeachother’s bids, and adding a sixth user does not enable additional changes to \mbox{\code{leadingBid}~\cite{KaiserKroening2010}}. The bounded system, known as a harness, in \cref{Fig:Harness} assigns the zero-account to address 0, the smart contract account to address 1, the manager to address 2, the arbitrary senders to addresses 3 and 4, and then executes an unbounded sequence of arbitrary function calls. Establishing \prop{1} on the harness requires finding its inductive strengthening. A strengthening such as \prop{1b} (or, in general, a counterexample violating \prop{1}) can be found by an SMC, directly on the harness code. The above bound for \prop{1} also works for checking all control-reachability properties of \code{Auction}. This, for example, follows by applying the results of~\cite{KaiserKroening2010}. That is, \code{Auction} has a \emph{Small Model Property (SMP)}~(e.g.,~\cite{KaiserKroening2010,AbdullaHH13}) for such properties. However, not all contracts enjoy an SMP. Consider \prop{2}: ‘‘\emph{The sum of all active bids is at least \code{leadingBid}}.’’ \code{Auction} satisfies \prop{2} since the leading bid is never withdrawn. To prove \code{Auction} satisfies \prop{2}, we instrument the code to track the current sum, through the highlighted lines in \cref{Fig:Auction}. With the addition of \code{\_sum}, \code{Auction} no longer enjoys an SMP. Intuitively, each user enables new combinations of \code{\_sum} and \code{leadingBid}. As a proof, assume that there are $N$ users (other than the zero-account, the smart contract account, and the manager) and let $S_N = 1 + 2 + \cdots + N$. In every execution with $N$ users, if \code{leadingBid} is $N + 1$, then \code{\_sum} is less than $S_{N + 1}$, since active bids are unique and $S_{N + 1}$ is the sum of $N + 1$ bids from $1$ to $N + 1$. However, in an execution with $N + 1$ users, if the $i$-th user has a bid of $i$, then \code{leadingBid} is $N + 1$ and \code{\_sum} is $S_{N + 1}$. Therefore, increasing $N$ extends the reachable combinations of \code{\_sum} and \code{leadingBid}. For example, if $N = 2$, then $S_3 = 1 + 2 + 3 = 6$. If the leading bid is $3$, then the second highest bid is at most $2$, and, therefore, $\mathsol{\_sum} \le 5 < S_3$. However, when $N = 3$, if the three active bids are $\{ 1, 2, 3 \}$, then \code{\_sum} is $S_3$. Therefore, instrumenting \code{Auction} with \code{\_sum} violates the SMP of the original \code{Auction}. Despite the absence of such an SMP, each function of \code{Auction} interacts with at most one user per transaction. Each user is classified as either the zero-account, the smart contract, the manager, or an arbitrary sender. In fact, all arbitrary senders are indistinguishable with respect to \prop{2}. For example, if there are exactly three active bids, $\{ 2, 4, 8 \}$, it does not matter which user placed which bid. The leading bid is $8$ and the sum of all bids is $14$. On the other hand, if the leading bid is $8$, then each participant of \code{Auction} must have a bid in the range of $0$~to~$8$. To take advantage of these classes, rather than analyze \code{Auction} relative to all $2^{160}$ users, it is sufficient to analyze \code{Auction} relative to a representative user from each class. In our running example, there must be representatives for the zero-account, the smart contract account, the manager, and an (arbitrary) sender. The key idea is that each representative user can correspond to one or \emph{many} concrete users. Intuitively, each representative user summarizes the concrete users in its class. If a representative’sclasscontainsasingleconcreteuser,thenthere␣␣isnodifferencebetweentheconcreteuserandtherepresentativeuser.For␣␣␣␣␣example,thezero-account,thesmartcontractaccount,andthemanagereach␣␣␣␣␣correspondtosingleconcreteusers.Theaddressesoftheseusers,andinturn,theirbids,areknownwithabsolutecertainty.Ontheotherhand,therearemany␣␣␣␣␣␣␣␣arbitrarysenders.Sincesendersareindistinguishablefromeachother,the␣␣␣␣␣preciseaddressoftherepresentativesenderisunimportant.Whatmattersis␣␣␣␣thattherepresentativesenderdoesnotshareanaddresswiththezero-account,thesmartcontractaccount,northemanager.However,thismeansthatatthe␣␣␣␣startofeachtransactionthelocationoftherepresentativesenderisnot␣␣␣␣␣␣absolute,and,therefore,thesenderhasarangeofpossiblebids.Toaccount␣␣␣forthis,weintroduceapredicatethatistrueofallinitialbids,andholds␣␣inductivelyacrossalltransactions.Weprovidethispredicatemanually,anduse␣␣␣␣␣␣␣␣ittoover-approximateallpossiblebids.Anobviouspredicatefor␣␣␣␣␣␣\code{Auction}isthatallbidsareatmost\mbox{\code{leadingBid},}butthis␣␣predicateisnotstrongenoughtoprove\prop{2}.Forexample,the␣␣␣␣␣␣representativesendercouldfirstplaceabidof$10$,andthen(spuriously)␣␣␣␣withdrawabidof$5$,resultinginasumof$5$butaleadingbidof$10$.A␣␣␣strongerpredicate,thatisadequatetoprove\prop{2},isgivenby$\theta_U$:‘‘\emph{Eachbidisatmost\mbox{\code{leadingBid}.}Ifabidisnot␣␣␣\mbox{\code{leadingBid},}thenitssumwith\code{leadingBid}isatmost␣␣␣␣␣␣␣␣\mbox{\code{\_sum}.}}’␣␣␣␣␣␣␣␣␣Given$\theta_U$,\prop{2}canbeverifiedbyanSMC.Thisrequiresanew␣␣␣␣␣␣␣harness,withrepresentative,ratherthanconcrete,users.Thenewharness,␣␣␣␣␣\cref{Fig:Harness}(nowincludingthehighlightedlines),issimilartotheSMPharnessinthatthezero-account,thesmartcontractaccount,andthemanager␣␣␣accountareassignedtoaddresses0,1,and2,respectively,followedbyan␣␣␣␣␣unboundedsequenceofarbitrarycalls.However,thereisnowasinglesender␣␣␣␣thatisassignedtoaddress~3(line~\ref{line:harness-instr-sender}).Thatis,␣␣theharnessusesafixedconfigurationofrepresentativesinwhichthefourth␣␣␣representativeisthesender.Beforeeachfunctioncall,thesender’s bid is set to a non-deterministic value that satisfies $\theta_U$ (lines~\ref{line:harness-instr-start}--\ref{line:harness-instr-end}). If the new harness and \prop{2} are provided to an SMC, the SMC will find an inductive strengthening such as, ‘‘\emph{The leading bid is at most the sum of all bids}.’’ The harness in \cref{Fig:Harness} differs from existing smart contract verification techniques in two ways. First, each address in \cref{Fig:Harness} is an abstraction of one or more concrete users. Second, \code{msg.sender} is restricted to a finite address space by lines~\ref{line:harness-instr-sender-start}~to~\ref{line:harness-instr-sender}. If these lines are removed, then an inductive invariant must constrain all cells of \code{bids}, to accommodate \code{bids[msg.sender]}. This requires quantified invariants over arrays that is challenging to automate. By introducing lines~\ref{line:harness-instr-sender-start}~to~\ref{line:harness-instr-sender}, a quantifier-free predicate, such as our $\theta_U$, can directly constrain cell \code{bids[msg.sender]} instead. Adding lines \ref{line:harness-instr-sender-start}--\ref{line:harness-instr-sender} makes the contract finite state. Thus, its verification problem is decidable and can be handled by existing SMCs. However, as illustrated by \prop{2}, the restriction on each user must not exclude feasible counterexamples. Finding such a restriction is the focus of this paper. In this paper, we present a new approach to smart contract verification. We construct finite-state abstractions of parameterized smart contracts, known as \emph{local bundles}. A local bundle generalizes the harness in \cref{Fig:Harness}, and is constructed from a set of representatives and their predicates. When a local bundle and a property are provided to an SMC, there are three possible outcomes. First, if a predicate does not over-approximate its representative, a counterexample to the predicate is returned. Second, if the predicates do not entail the property, then a counterexample to verification is returned (this counterexample refutes the proof, rather than the property itself). Finally, if the predicates do entail the property, then an inductive invariant is returned. As opposed to deductive smart contract solutions, our approach finds inductive strengthenings automatically~\cite{HajduJovanovic2019,ZhongCheang2020}. As opposed to other model checking solutions for smart contracts, our approach is not limited to pre- and post-conditions~\cite{KalraGoel2018}, and can scale to $2^{160}$ users~\cite{Kolb2020}. Key theoretical contributions of this paper are to show that verification with local bundle abstraction is an instance of Parameterized Compositional Model Checking (PCMC)~\cite{NamjoshiTrefler2016} and the automation of the side-conditions for its applicability. Specifically, \cref{Thm:SafetyCheck} shows that the local bundle abstraction is a sound proof rule, and a static analysis algorithm (\code{PTGBuilder} in \cref{sec:communication}) computes representatives so that the rule is applicable. Key practical contributions are the implementation and the evaluation of the method in a new smart contract verification tool \smartace, using \seahorn~\cite{GurfinkelKahsai2015} for SMC. \smartace takes as input a contract and a predicate. Representatives are inferred automatically from the contract, by analyzing the communication in each transaction. The predicate is then validated by \seahorn, relative to the representatives. If the predicate is correct, then a local bundle, as in \cref{Fig:Harness}, is returned. The rest of the paper is structured as follows. \cref{Sec:Background} reviews parameterized verification. \cref{Sec:SyntaxSemantics} presents MicroSol, a subset of Solidity with network semantics. \cref{sec:communication} relates user interactions to representatives. We formalize user interactions as \emph{Participation Topologies (PTs)}, and define \emph{PT Graphs (PTGs)} to over-approximate PTs for arbitrarily many users. Intuitively, each PTG over-approximates the set of representatives. We show that a PTG is computable for every MicroSol program. \cref{sec:locality} defines local bundles and proves that our approach is sound. \cref{sec:eval} evaluates \smartace and shows that it can outperform \verx, a state-of-the-art verification tool, on all but one \verx benchmark.

2 Background

In this section, we briefly recall Parameterized Compositional Model Checking (PCMC) [NamjoshiTrefler2016]. We write 𝐮=(u0,,un1)\mathbf{u}=(u_{0},\ldots,u_{n-1}) for a vector of nn elements, and 𝐮i\mathbf{u}_{i} for the ii-th element of 𝐮\mathbf{u}. For a natural number nn\in\mathbb{N}, we write [n][n] for {0,,n1}\{0,\ldots,n-1\}.

Labeled Transition Systems.

A labeled transition system (LTS), MM, is a tuple (S,P,T,s0)(S,P,T,s_{0}), where SS is a set of states, PP is a set of actions, T:S×P2ST:S\times P\to 2^{S} is a transition relation, and s0Ss_{0}\in S is an initial state. MM is deterministic if TT is a function, T:S×PST:S\times P\to S. A (finite) trace of MM is an alternating sequence of states and actions, (s0,p1,s1,,pk,sk)(s_{0},p_{1},s_{1},\ldots,p_{k},s_{k}), such that i[k]si+1T(si,pi+1)\forall i\in[k]\cdot s_{i+1}\in T(s_{i},p_{i+1}). A state ss is reachable in MM if ss is in some trace (s0,p1,,sk)(s_{0},p_{1},\ldots,s_{k}) of MM; that is, i[k+1]si=s\exists i\in[k+1]\cdot s_{i}=s. A safety property for MM is a subset of states (or a predicate111Abusing notation, we refer to a subset of states φ\varphi as a predicate and do not distinguish between the syntactic form of φ\varphi and the set of states that satisfy it.) φS\varphi\subseteq S. MM satisfies φ\varphi, written MφM\models\varphi, if every reachable state of MM is in φ\varphi.

Many transition systems are parameterized. For instance, a client-server application is parameterized by the number of clients, and an array-manipulating program is parameterized by the number of cells. In both cases, there is a single control process that interacts with many user processes. Such systems are called synchronized control-user networks (SCUNs) [NamjoshiTrefler2016]. We let NN be the number of processes, and [N][N] be the process identifiers. We consider SCUNs in which users only synchronize with the control process and do not execute code on their own.

An SCUN 𝒩\mathcal{N} is a tuple (SC,SU,PI,PS,TI,TS,c0,u0)(S_{C},S_{U},P_{I},P_{S},T_{I},T_{S},c_{0},u_{0}), where SCS_{C} is a set of control states, SUS_{U} a set of user states, PIP_{I} a set of internal actions, PSP_{S} a set of synchronized actions, TI:SC×PISCT_{I}:S_{C}\times P_{I}\to S_{C} an internal transition function, TS:SC×SU×PSSC×SUT_{S}:S_{C}\times S_{U}\times P_{S}\to S_{C}\times S_{U} a synchronized transition function, c0SCc_{0}\in S_{C} is the initial control state, and u0SUu_{0}\in S_{U} is the initial user state. The semantics of 𝒩\mathcal{N} are given by a parameterized LTS, M(N):=(S,P,T,s0)M(N)\mathbin{:=}(S,P,T,s_{0}), where S:=SC×(SU)NS\mathbin{:=}S_{C}\times\left(S_{U}\right)^{N}, P:=PI(PS×[N])P\mathbin{:=}P_{I}\cup\left(P_{S}\times[N]\right), s0:=(c0,u0,,u0)s_{0}\mathbin{:=}(c_{0},u_{0},\ldots,u_{0}), and T:S×PST:S\times P\rightarrow S such that: (1) if pPIp\in P_{I}, then T((c,𝐮),p)=(TI(c,p),𝐮)T((c,\mathbf{u}),p)=(T_{I}(c,p),\mathbf{u}), and (2) if (p,i)PS×[N](p,i)\in P_{S}\times[N], then T((c,𝐮),(p,i))=(c,𝐮)T((c,\mathbf{u}),(p,i))=(c^{\prime},\mathbf{u}^{\prime}) where (c,𝐮i)=TS(c,𝐮i,p)(c^{\prime},\mathbf{u}^{\prime}_{i})=T_{S}(c,\mathbf{u}_{i},p), and j[N]\{i}𝐮j=𝐮j\forall j\in[N]\backslash\{i\}\cdot\mathbf{u}^{\prime}_{j}=\mathbf{u}_{j}.

Parameterized Compositional Model Checking (PCMC).

Parameterized systems have parameterized properties [GurfinkelSharon2016, NamjoshiTrefler2016]. A kk-universal safety property [GurfinkelSharon2016] is a predicate φSC×(SU)k\varphi\subseteq S_{C}\times(S_{U})^{k}. A state (c,𝐮)(c,\mathbf{u}) satisfies predicate φ\varphi if {i1,,ik}[N]φ(c,𝐮i1,,𝐮ik)\forall\{i_{1},\ldots,i_{k}\}\subseteq[N]\cdot\varphi(c,\mathbf{u}_{i_{1}},\ldots,\mathbf{u}_{i_{k}}). A parameterized system M(N)M(N) satisfies predicate φ\varphi if NM(N)φ\forall N\in\mathbb{N}\cdot M(N)\models\varphi. For example, Prop. 1 (Sec. 1) of {SimpleAuction} (\cref{Fig:Auction}) is $1$-universal: ‘‘\emph{For every user $u$, if \code{stop()} has been called, then $u$ is immutable}.’’ Proofs of $k$-universal safety employ compositional reasoning, e.g., \cite{AbdullaHH16,GurfinkelSharon2016,NamjoshiTrefler2016,OwickiGries1976}. Here, we use PCMC~\cite{NamjoshiTrefler2016}. The keys to PCMC are \emph{uniformity}---the property that finitely many neighbourhoods are distinguishable---and a \emph{compositional invariant}---a summary of the reachable states for each equivalence class, that is closed under the actions of every other equivalence class. For an SCUN, the compositional invariant is given by two predicates $\theta_C \subseteq S_C$ and $\theta_U \subseteq S_C \times S_U$ satisfying: \begin{enumerate} \item[\textbf{Initialization}] $c_0 \in \theta_C$ and $( c_0, u_0 ) \in \theta_U$; \item[\textbf{Consecution 1}] If $c \in \theta_C$, $( c, u ) \in \theta_U$, $p \in P_S$, and $( c’,u’ ) \in T_S( c, u, p )$, then $c\in\theta_C$and␣␣␣␣␣␣␣$(c’, u)\in\theta_U$;\item[\textbf{Consecution2}]␣␣If$c\in\theta_C$,$(c,u)\in\theta_U$,$p␣␣␣␣␣␣\inP_C$,and$c’ = T_I( c, p )$, then $c\in\theta_C$and$(c’, u ) \in \theta_U$; \item[\textbf{Non-Interference}] If $c \in \theta_C$, $( c, u ) \in \theta_U$, $( c, v ) \in \theta_U$, $u \neq v$, $p \in P_S$, and $( c’,u’ ) = T_S( c, u, p )$, then $( c’,v)\in\theta_C$.␣␣␣␣\end{enumerate}ByPCMC~\cite{NamjoshiTrefler2016},if$\forallc\in\theta_C\cdot\forall\{(c,u_1),\ldots,(c,u_k)\}\subseteq\theta_U\cdot\varphi(c,u_1,\ldots,␣␣u_k)$,then$M\models\varphi$.Thisisasanextensionof␣␣␣␣␣Owicki-Gries~\cite{OwickiGries1976},where$\theta_C$summarizestheacting␣␣␣␣␣processand$\theta_U$summarizestheinterferingprocess.Forthisreason,we␣␣call$\theta_C$the\emph{inductiveinvariant}and$\theta_U$the␣␣␣␣␣␣␣\emph{interferenceinvariant}.’

3 MicroSol: Syntax and Semantics

FName\displaystyle\langle\textrm{FName}\rangle ::=\displaystyle::= a valid function name
VName\displaystyle\langle\textrm{VName}\rangle ::=\displaystyle::= a valid variable name
CName\displaystyle\langle\textrm{CName}\rangle ::=\displaystyle::= a valid contract name
Literal\displaystyle\langle\textrm{Literal}\rangle ::=\displaystyle::= an integer, Boolean, or address literal
Types\displaystyle\langle\textrm{Types}\rangle ::=\displaystyle::= uintbooladdressmapping(address=>uint)CName\displaystyle\texttt{uint}\;\mid\;\texttt{bool}\;\mid\;\texttt{address}\;\mid\;\texttt{mapping}\texttt{(}\;\texttt{address}\;\texttt{=>}\;\texttt{uint}\;\texttt{)}\;\mid\;\langle\textrm{CName}\rangle
Operator\displaystyle\langle\textrm{Operator}\rangle ::=\displaystyle::= ==!=<>+-*/&&||!\displaystyle\texttt{==}\;\mid\;\texttt{!=}\;\mid\;\texttt{<}\;\mid\;\texttt{>}\;\mid\;\texttt{+}\;\mid\;\texttt{-}\;\mid\;\texttt{*}\;\mid\;\texttt{/}\;\mid\;\texttt{\&\&}\;\mid\;\texttt{||}\;\mid\;\texttt{!}
Expr\displaystyle\langle\textrm{Expr}\rangle ::=\displaystyle::= LiteralVNamethismsg.senderExprOperatorExpr\displaystyle\langle\textrm{Literal}\rangle\;\mid\;\langle\textrm{VName}\rangle\;\mid\;\texttt{this}\;\mid\;\texttt{msg.sender}\;\mid\;\langle\textrm{Expr}\rangle\;\langle\textrm{Operator}\rangle\;\langle\textrm{Expr}\rangle
address(VName)Expr.FName(Expr,)\displaystyle\;\mid\;\texttt{address}\texttt{(}\;\langle\textrm{VName}\rangle\;\texttt{)}\;\mid\;\langle\textrm{Expr}\rangle\texttt{.}\langle\textrm{FName}\rangle\;\texttt{(}\;\langle\textrm{Expr}\rangle\texttt{,}\;\dots\;\texttt{)}
FName(Expr,)Expr[Expr][Expr]\displaystyle\;\mid\;\langle\textrm{FName}\rangle\;\texttt{(}\;\langle\textrm{Expr}\rangle\texttt{,}\;\dots\;\texttt{)}\;\mid\;\langle\textrm{Expr}\rangle\;\texttt{[}\;\langle\textrm{Expr}\rangle\;\texttt{]}\;\dots\;\texttt{[}\;\langle\textrm{Expr}\rangle\;\texttt{]}
Assign\displaystyle\langle\textrm{Assign}\rangle ::=\displaystyle::= VName=ExprExpr=newCName(Expr,)\displaystyle\langle\textrm{VName}\rangle\;\texttt{=}\;\langle\textrm{Expr}\rangle\;\mid\;\langle\textrm{Expr}\rangle\;\texttt{=}\;\texttt{new}\;\langle\textrm{CName}\rangle\texttt{(}\;\langle\textrm{Expr}\rangle\texttt{,}\;\dots\;\texttt{)}
Expr[Expr][Expr]=Expr\displaystyle\;\mid\;\langle\textrm{Expr}\rangle\;\texttt{[}\;\langle\textrm{Expr}\rangle\;\texttt{]}\;\dots\;\texttt{[}\;\langle\textrm{Expr}\rangle\;\texttt{]}\;\texttt{=}\;\langle\textrm{Expr}\rangle
Decl\displaystyle\langle\textrm{Decl}\rangle ::=\displaystyle::= TypesVName\displaystyle\langle\textrm{Types}\rangle\;\langle\textrm{VName}\rangle
Stmt\displaystyle\langle\textrm{Stmt}\rangle ::=\displaystyle::= DeclAssignrequire(Expr)assert(Expr)return\displaystyle\langle\textrm{Decl}\rangle\;\mid\;\langle\textrm{Assign}\rangle\;\mid\;\texttt{require(}\;\langle\textrm{Expr}\rangle\;\texttt{)}\;\mid\;\texttt{assert(}\;\langle\textrm{Expr}\rangle\;\texttt{)}\;\mid\;\texttt{return}
if(Expr){Stmt}while(Expr){Stmt}Stmt;Stmt\displaystyle\;\mid\;\texttt{if}\texttt{(}\;\langle\textrm{Expr}\rangle\;\texttt{)}\;\texttt{\{}\;\langle\textrm{Stmt}\rangle\;\texttt{\}}\;\mid\;\texttt{while}\texttt{(}\;\langle\textrm{Expr}\rangle\;\texttt{)}\;\texttt{\{}\;\langle\textrm{Stmt}\rangle\;\texttt{\}}\;\mid\;\langle\textrm{Stmt}\rangle\texttt{;}\;\langle\textrm{Stmt}\rangle
Ctor\displaystyle\langle\textrm{Ctor}\rangle ::=\displaystyle::= constructor(Decl,)public{Stmt}\displaystyle\texttt{constructor}\;\texttt{(}\;\langle\textrm{Decl}\rangle\texttt{,}\;\dots\;\texttt{)}\;\texttt{public}\;\texttt{\{}\;\langle\textrm{Stmt}\rangle\;\texttt{\}}
Func\displaystyle\langle\textrm{Func}\rangle ::=\displaystyle::= functionFName(Decl,)public{Stmt}\displaystyle\texttt{function}\;\langle\textrm{FName}\rangle\;\texttt{(}\;\langle\textrm{Decl}\rangle\texttt{,}\;\dots\;\texttt{)}\;\texttt{public}\;\texttt{\{}\;\langle\textrm{Stmt}\rangle\;\texttt{\}}
Contract\displaystyle\langle\textrm{Contract}\rangle ::=\displaystyle::= contractCName{Decl;;CtorFunc}\displaystyle\texttt{contract}\;\langle\textrm{CName}\rangle\;\texttt{\{}\;\langle\textrm{Decl}\rangle\texttt{;}\;\dots\texttt{;}\;\langle\textrm{Ctor}\rangle\;\langle\textrm{Func}\rangle\;\dots\;\texttt{\}}
Bundle\displaystyle\langle\textrm{Bundle}\rangle ::=\displaystyle::= ContractContract\displaystyle\langle\textrm{Contract}\rangle\;\langle\textrm{Contract}\rangle\dots
Figure 3: The formal grammar of the MicroSol language.

This section provides network semantics for MicroSol, a subset of Solidity222https://docs.soliditylang.org/. Like Solidity, MicroSol is an imperative object-oriented language with built-in communication operations. The syntax of MicroSol is in Fig. 3. MicroSol restricts Solidity to a core subset of communication features. For example, MicroSol does not include inheritance, cryptographic operations, or mappings between addresses. In our evaluation (LABEL:sec:eval), we use a superset of MicroSol, called MiniSol (see LABEL:Appendix:MiniSol), that extends our semantics to a wider set of smart contracts. Throughout this section, we illustrate MicroSol using {Auction} in \cref{Fig:Auction}. A MicroSol \emph{smart contract} is similar to a class in object-oriented programming, and consists of variables, and transactions (i.e., functions) for users to call. A transaction is a deterministic sequence of operations. Each smart contract user has a globally unique identifier, known as an \emph{address}. We view a smart contract as operating in an SCUN: the control process executes each transaction sequentially, and the user processes are contract users that communicate with the control process. Users in the SCUN enter into a transaction through a synchronized action, then the control process executes the transaction as an internal action, and finally, the users are updated through synchronized actions. For simplicity of presentation, each transaction is given as a global transition. A constructor is a special transaction that is executed once after contract creation. Calls to \code{new} (i.e., creating new smart contracts) are restricted to constructors. \code{Auction} in \cref{Fig:Auction} is a smart contract that defines a constructor (line~\ref{line:constructor}), three other functions (lines~\ref{line:bid}, \ref{line:withdraw}, and~\ref{line:stop}), and four state variables (lines~\ref{line:vars-start}--\ref{line:vars-end}). MicroSol has four types: \emph{address}, \emph{numeric} (including \code{bool}), \emph{mapping}, and \emph{contract reference}. Address variables prevent arithmetic operations, and numeric variables cannot cast to address variables. Mapping and contract-reference variables correspond to dictionaries and object pointers in other object-oriented languages. Each typed variable is further classified as either \emph{state}, \emph{input}, or \emph{local}. We use \emph{role} and \emph{data} to refer to state variables of address and numeric types, respectively. Similarly, we use \emph{client} and \emph{argument} to refer to inputs of address and numeric types, respectively. In \code{Auction} of \cref{Fig:Auction}, there is $1$ role \mbox{(\code{manager}),} $2$ contract data \mbox{(\code{leadingBid}} and \mbox{\code{stopped}),} $1$ mapping \mbox{(\code{bids})}, $1$ client common to all transactions \mbox{(\code{msg.sender})}, and at most $1$ argument in any transaction \mbox{(\code{amount}).} Note that in MicroSol, \emph{user} denotes any user process within a SCUN. A \emph{client} is defined relative to a transaction, and denotes a user passed as an input. \newcommand{\tran}{\mathit{tr}} \newcommand{\cM}{\mathcal{M}} \paragraph{Semantics of MicroSol.} Let $\cC$ be a MicroSol program with a single transaction $\tran$ (see \appendixcite{Appendix:Lts} for multiple transactions). An $N$-user \emph{bundle} is an $N$-user network of several (possibly identical) MicroSol programs. The semantics of a bundle is an LTS, $\lts( \cC, N ) \gets ( S, P, f, s_0 )$, where $S_C \gets \control( \cC, [N] )$ is the set of control states, $S_U \gets \user( \cC, [N] )$, is the set of user states, $s_{\bot}$ is the error state, $S \subseteq \left( S_C \cup \{ s_{\bot} \} \right) \times (S_U)^N$ is the set of LTS states, $P \gets \inputs( \cC, [N] )$ is the set of actions, $f: S \times P \rightarrow S$ is the \emph{transition function}, and $s_0$ is the initial state. We assume, without loss of generality, that there is a single control process\footnote{Restrictions place on \code{new} ensure that the number of MicroSol smart contracts in a bundle is a static fact. Therefore, all control states are synchronized, and can be combined into a product machine.}. Let $\bbD$ be the set of $256$-bit unsigned integers. The state space of a smart contract is determined by the address space, $\cA$, and the state variables of $\cC$. In the case of $\lts( \cC, N )$, the address space is fixed to $\cA = [N]$. Assume that $n$, $m$, and $k$ are the number of roles, data, and mappings in $\cC$, respectively. State variables are stored by their numeric indices (i.e., variable~$0$, $1$, etc.). Then, $\control( \cC, \cA ) \subseteq \cA^n \times \bbD^m$ and $\user( \cC, \cA ) \subseteq \cA \times \bbD^k$. For $c = ( \vx, \vy ) \in \control( \cC, \cA)$, $\role( c, i ) = \vx_i$ is the $i$-th role and $\data( c, i ) = \vy_i$ is the $i$-th datum. For $u = (z, \vy) \in \user( \cC, \cA )$, $z$ is the address of $u$, and $\rec( u ) = \vy$ are the mapping values of $u$. Similarly, actions are determined by the address space, $\cA$, and the input variables of $\tran$. Assume that $q$ and $r$ are the number of clients and arguments of $\tran$, respectively. Then $\inputs( \cC, \cA ) \subseteq \cA^q \times \bbD^r$. For $p = (\vx, \vy) \in \inputs( \cC, \cA )$, $\client( p, i ) = \vx_i$ is the $i$-th client in $p$ and $\args( p, i ) = \vy_i$ is the $i$-th argument in $p$. For a fixed $p$, we write $f_p( s, \vu )$ to denote $f( (s, \vu), p )$. The initial state of $\lts( \cC, N )$ is $s_0 \gets (c, \vu) \in \control( \cC, [n] ) \times \user( \cC, [n] )^N$, where $c = ( \vec{0}, \vec{0} )$, $\forall i \in [N] \cdot \rec(\vu_i) = \vec{0}$, and $\forall i \in [N] \cdot \id( \vu_i ) = i$. That is, all variables are zero-initialized and each user has a unique address. An $N$-user transition function is determined by the (usual) semantics of $\tran$, and a \emph{bijection} from addresses to user indices, $\cM: \cA \rightarrow [N]$. If $\cM( a ) = i$, then address $a$ belongs to user $\vu_i$. In the case of $\lts( \cC, N )$, the $i$-th user has address $i$, so $\cM(i) = i$. We write $f \gets \bbrackfn{\cC}_{\cM}$, and given an action $p$, $f_p$ updates the state variables according to the source code of $\tran$ with respect to $\cM$. If an \code{assert} fails or an address is outside of $\cA$, then the error state $s_{\bot}$ is returned. If a \code{require} fails, then the state is unchanged. Note that $f$ preserves the address of each user. For example, $\lts(\text{Auction}, 4) = (S, P, f, s_0)$ is the $4$-user bundle of \code{Auction}. Assume that $(c, \vu)$ is the state reached after evaluating the constructor. Then $\role( c, 0 ) = 2$, $\data( c, 0 ) = 0$, $\data( c, 1 ) = 0$, and $\forall i \in [4] \cdot \rec( \vu_i )_0 = 0$. That is, the manager is at address 2, the leading bid is 0, the auction is not stopped, and there are no active bids. This is because variables are zero-indexed, and \code{stopped} is the second numeric variable (i.e., at index 1). If the user at address $3$ placed a bid of $10$, this corresponds to $p \in P$ such that $\client( p, 0 ) = 3$ and $\args( p, 0 ) = 10$. A complete LTS for this example is in \appendixcite{Appendix:Lts}. \paragraph{Limitations of MicroSol.} MicroSol places two restrictions on Solidity. First, addresses are not numeric. We argue that this restriction is reasonable, as address manipulation is a form of pointer manipulation. Second, \code{new} must only appear in constructors. In our evaluation (\cref{sec:eval}), all calls to \code{new} could be moved into a constructor with minimal effort. We emphasize that the second restriction does not preclude the use of abstract interfaces for arbitrary contracts.

4 Participation Topology

The core functionality of any smart contract is communication between users. Usually, users communicate by reading from and writing to designated mapping entries. That is, the communication paradigm is shared memory. However, it is convenient in interaction analysis to re-imagine smart contracts as having rendezvous synchronization in which users explicitly participate in message passing. In this section, we formally re-frame smart contracts with explicit communication by defining a (semantic) participation topology and its abstractions.

Refer to caption
(a) A PT for 44 users and a fixed action.
Refer to caption
(b) The PTG from {{{PTGBuilder}.label{Fig:Topology:PTG}}}
\RawCaption
(c) A PT of {Auction} contrasted with a PTG for{{{Auction}.label{Fig:Topology}}}

A user uu participates in communication during a transaction ff whenever the state of uu affects execution of ff or ff affects a state of uu. We call this influence. For example, in Fig. 1, the sender influences