Presented at FMBC 2020 Formal Formal Specif Specification ication and Verific and Verification ation of Solid of Solidity ity Contracts Contracts with E with Events vents Ákos Hajdu 1 , Dejan Jovanović 2 , Gabriela Ciocarlie 2 1 Budapest University of Technology and Economics 2 SRI International
Solidity Smart Contracts and Events contract Token { mapping(address=>uint) balances; uint total; event initialized(address from, uint amount); event transferred(address from, address to, uint amount); constructor(uint _total) public { balances[msg.sender] = total = _total; emit initialized(msg.sender, total); } function transfer(address to, uint amount) public { require(balances[msg.sender] >= amount && msg.sender != to); balances[msg.sender] -= amount; balances[to] += amount; emit transferred(msg.sender, to, amount); } } 2
Solidity Events • Stored in blockchain logs E1(x) E1(x) • Contract communicates with user E2(x,y) E2(x,y) – Important state changes • Abstract view of execution E2(x,y) E1(x) – Relevant aspect to each user 3
Motivation Was there a change when emitted? Do we always emit if balances change? Can we trust (rely on) the emitted events? Is the amount correct? Not really… 4
Formal Specification of Events • What state variable(s) do events track? – Emit event iff there was a change contract Token { mapping(address=>uint) balances; uint total; /// @notice tracks-changes-in balances /// @notice tracks-changes-in total event initialized(address from, uint amount); /// @notice tracks-changes-in balances event transferred(address from, address to, uint amount); } 5
Formal Specification of Events • What events can functions emit? – Similar to Java throws contract Token { /// @notice emits initialized constructor(uint _total) public { ... } /// @notice emits transferred function transfer(address to, uint amount) public { ... } } 6
Formal Specification of Events • What are the conditions before and at the emit? contract Token { /// @notice precondition balances[from] == 0 /// @notice postcondition balances[from] == amount /// @notice postcondition total == amount event initialized(address from, uint amount); /// @notice precondition balances[from] >= amount /// @notice postcondition balances[from] == before(balances[from]) - amount /// @notice postcondition balances[to] == before(balances[to]) + amount event transferred(address from, address to, uint amount); } 7
DEMO 8
Formal Verification • Where to check if an event has been emitted? – Cannot check immediately (modification in multiple steps) • Where to check preconditions? – What does “before the change” exactly mean? 9
Checkpoints function transfer(address to, uint amount) public { require(balances[msg.sender] >= amount && msg.sender != to); ... Before checkpoint balances[msg.sender] -= amount; First time variable changes • balances[to] += amount; Save state (for precondition) • ... emit transferred(msg.sender, to, amount); ... Emit } Check pre/post • Clear before/after checkpoint • After checkpoint Static barrier • Latest point to emit • E.g., function end • 10
github.com/SRI-CSL/solidity Overview solc-verify .sol .bpl Extended compiler Boogie μ □ β → λ verifier ∆ v Σ →φ Verification Back-annotation conditions Boogie program w/ Solidity contract Proofs instrumentation with specification SMT solvers 11
Instrumentation mapping(address=>uint) bal_old; mapping(address=>uint) balances; bool bal_modif; new vars /// @notice emits transferred function transfer(address to, uint amount) public { assume clear require(!bal_modif); require(balances[msg.sender] >= amount && msg.sender != to); check modif balances[msg.sender] -= amount; if (!bal_modif) { if (!bal_modif) { check modif bal_old = balances; bal_old = balances; balances[to] += amount; bal_modif = true; } bal_modif = true; } emit specs emit transferred(msg.sender, to, amount); after checkpt assert(bal_modif); } assert(bal_old[msg.sender] >= amount); assert(balances[msg.sender] == bal_old[msg.sender]-amount); assert(!bal_modif); assert(balances[to] == bal_old[to] + amount); bal_modif = false; 12
Discussion • We used solc-verify – Modular verifier based on Boogie and SMT – Can work with other verifiers (supporting assertions) • After checkpoints – Depend on verification approach – Modular verification: loop boundaries as well 13
Conclusions • Solidity events provide abstract view E1(x) E1(x) E2(x,y) E2(x,y) • Formal specification and verification • In-code annotations E2(x,y) E1(x) • Checkpoints • Instrumentation contract Token { mapping(address=>uint) balances; uint total; arxiv.org/abs/2005.10382 /// @notice tracks-changes-in balances /// @notice tracks-changes-in total event initialized(address from, uint amount); github.com/SRI-CSL/solidity /// @notice tracks-changes-in balances event transferred(address from, address to, uint amount); } 14
Recommend
More recommend