Certifying functional correctness of Ethereum smart contracts
- Dr. Petar Tsankov
Certifying functional correctness of Ethereum smart contracts Dr. - - PowerPoint PPT Presentation
Certifying functional correctness of Ethereum smart contracts Dr. Petar Tsankov Co-founder and Chief scientist, ChainSecurity Senior researcher, ICE center, ETH Zurich @ptsankov Inter-disciplinary research center at Next-generation blockchain
https://chainsecurity.com @chain_security
contract Token { mapping(addr=>uint) balances; function balanceOf(address a){ return balances[a]; } function transfer(address to, uint n){ balances[msg.sender] -= n; balances[to] += n; }
contract Token { mapping(addr=>uint) balances; function balanceOf(address a){ return balances[a]; } function transfer(address to, uint n){ balances[msg.sender] -= n; balances[to] += n; }
contract Token { mapping(addr=>uint) balances; function balanceOf(address a){ return balances[a]; } function transfer(address to, uint n){ balances[msg.sender] -= n; balances[to] += n; }
mapping(address => uint) deposits; function deposit() { .. } function withdraw() { .. } function claimRefund() { .. }
uint raised; uint goal; uint closeTime; function invest() { .. } function close(){ .. }
always sum(Escrow.deposits) == Escrow.balance)
Initial state
invest(0) invest(9999)
invest (0) invest(9999) claimRefund()
...
Unbounded depth Infeasible to brute-force width
... claimRefund()
Can miss errors
Can miss errors
Can mi miss er errors
Initial state
invest(0) invest(9999)
invest (0) invest(9999) claimRefund()
... ... claimRefund()
Initial state
invest(0) invest(9999)
invest (0) invest(9999) claimRefund()
... ... claimRefund()
Can miss errors
Can mi miss er errors
Prove ves absence of errors
invest(0) invest(9999)
invest (0) invest(9999) claimRefund()
... ... claimRefund()
invest(0) invest(9999)
invest (0) invest(9999) claimRefund()
... ... claimRefund()
mapping(address => uint) deposits; function claimRefund(){..}
(always Escrow.claimRefund ==> !before(sum(deposits) >= 10000)
always Escrow.deposit(address) ==> (msg.sender == Escrow.owner)
always Escrow.deposit(address) ==> (msg.sender == Escrow.owner) always (now > Vault.refundTime + 1 week) ==> ! Vault.refund(uint256)
always Escrow.deposit(address) ==> (msg.sender == Escrow.owner) always (now > Vault.refundTime + 1 week) ==> ! Vault.refund(uint256)
always !(once(state == REFUND) && once(state == FINALIZED)
always Escrow.deposit(address) ==> (msg.sender == Escrow.owner) always (now > Vault.refundTime + 1 week) ==> ! Vault.refund(uint256)
always totalSupply == sum(balances)
always !(once(state == REFUND) && once(state == FINALIZED)
always Escrow.deposit(address) ==> (msg.sender == Escrow.owner) always (now > Vault.refundTime + 1 week) ==> ! Vault.refund(uint256)
always totalSupply == sum(balances)
always !(once(state == REFUND) && once(state == FINALIZED)
always Token.totalSupply >= Sale.issuance
always Escrow.deposit(address) ==> (msg.sender == Escrow.owner) always (now > Vault.refundTime + 1 week) ==> ! Vault.refund(uint256)
always totalSupply == sum(balances)
always (! once(state == REFUND) && once(state == FINALIZED)
always Token.totalSupply >= Sale.issuance
Initial state
invest(X) claimRefund(Y)
invest(X) claimRefund(Y)
“Investors can claim refunds only if the sum of deposits never exceeded 10,000 ether “
Smart contract
mapping(address => uint) deposits; function claimRefund(){..}
(always Escrow.claimRefund ==> !before(sum(deposits) >= 10000)
Formal property Ve Verified Ma May not hold
Initial state
invest(X) claimRefund(Y) invest(X) claimRefund(Y)
Bounded depth Feasible width
Formal verification Automated testing Manual review
RELIABILITY
Can miss errors
Can mis miss er errors
verification
Proves absence of errors
contract Token { mapping(addr=>uint) balances; function balanceOf(address a){ return balances[a]; } function transfer(address to, uint n){ balances[msg.sender] -= n; balances[to] += n; }Must not fail!