Lecture 10 A2 - will post tonight - due in two weeks The DAO - $72M USD in Ether Decentralized Dragon's Den or Shark's Tank A pot of money that you could contribute to and receive voting shares for You vote on funding projects The attack happened but the stolen funds sat quarantined for 30 days This means the stolen funds were not circulated and so a roll back was possible Ethereum project put in a special block that destructed the DAO contract and refunded everyone's money but the block is invalid --- so need consensus of the network to make an exception and accept it Most went with undoing the DAO attack and this chain is called Ethereum Some objected and did not undo the attack --- their chain is called Ethereum Classic Today ETC trades at about 10% the value of Ether The bug: reentrance / recursive calls Back to Ethereum External accounts - works like Bitcoin Contract accounts - running smart contracts; work by your design Alice and Bob want to use Ethereum like Bitcoin Use external accounts Alice pays Bob How does Bob know he was paid? Consulting the blockchain Automated by his client He sits down at a new paper, parse the whole blockchain to figure out transaction history Use a contract as a wallet with more features Can log all transactions in the state Can notify the use of transactions Can use multi-signatures or fancy access structures Ethereum client has one built in called a wallet and it is exposed in the UI
Alice pays Bob Alice pays to Bob's wallet smart contract Bob's wallet only runs if someone calls a function on it No code runs by itself on Ethereum IDEA! What if when you transfer money to a smart contract, that contract is allowed to run some code at that point? Issue 1: Which function in the smart contract will run when it receives money? Convention that it will run a special function with a special name What was the name? No name (empty string) function() payable { Fallback function Payable enables it to receive money when called Fallback function is also called if the function that is called cannot be found Issue 2: Gas Who pays for the fallback function to run? Recall the fallback in Contract B is being triggered by Contract A sending money to the address of Contract B (for whatever reason). Someone is paying for Contract A to run this function; why should they pay for Contract B as well? Paying contract pays the gas but can set a gas limit when it transfers the money If it runs out of gas (or fails for other reasons), an exception is thrown and/or the transfer function returns a boolean of false address.send(10) -> send 10 wei to address -> if error, it will return false, fallback function that is invoked is limited to 2300 gas address.transfer(10) -> same as send but throws an exception instead, fallback function that is invoked is limited to 2300 gas address.call.value(10)() -> old school way of sending money, returns false, uses whatever gas is available from the calling function address.send(10) = address.call.gas(0).value(10)() address.transfer.gas(120000)(10) -> run transfer with more gas Issue 3: code flow control When you transfer money to an address and the address is a contract,
you are turning control over to someone else's code that might be malicious and can do whatever it wants (within the gas you give it) // http://www.blunderingcode.com/writing-secure-solidity/ contract Victim { mapping (address => uint) userbalances; if (msg.sender.call.value(userbalances[msg.sender])()) { function() payable { userbalances[msg.sender] += msg.value; Contract contains a list of users and their "balances" in ledger as the data structure, and it also contains Ether (attached to the address) For example, contract might hold 10 Ether and have: A_address 5 B_address 3 C_address 2 D_address 0 Alice calls withdraw. She does it from an account. msg.sender will be her account Withdraw finds the balance of her account (5), as stored in userbalances, and transfers her that amount of money (5). **** If it succeeds, her balance is made to be 0. If it does not, the balance does not update. During **** Alice gets to run her fallback function
if (msg.sender.call.value(userbalances[msg.sender])()) { Alice's fallback function: What if Alice in her fallback function calls withdraw again? if (msg.sender.call.value(userbalances[msg.sender])()) // if (alice.call.value(5)())... // if (alice.call.value(5)() -> Alice's fallback) // if ( Alice's fallback ) // if ( withdraw ) // if ( if (alice.call.value(5)()) ) // if ( if ( if ( if ())))
Example of fallback function contract Attacker { Victim v; function Attacker(address dest) { v = Victim(dest); function attack() { v.call.value(msg.value)(); v.withdraw(); function() payable { if (msg.gas > 100000) { v.withdraw(); Mitigations: 3 approaches (not mutually exclusive) 1) Don't use call to send money, use transfer or send --> fallback function still runs but it is limited in terms of Gas to 2300 (which is thought to not be enough to do anything malicious) 2) Do the logic that updates the state before (not after) calling the transfer function uint balance = userbalances[msg.sender]; if (msg.sender.call.value(balance)()) { else{ userbalances[msg.sender] = balance;
3) Control flow integrity -> lock down who can enter a function and from where Locks -> States State Machine where before withdraw is called, the state is "open" and the first of line of withdraw will check that the state is open; the second changes the state to closed; then you add your code enum States {Open, Closed; States state; require state=states.open; state=states.closed; if (msg.sender.call.value(userbalances[msg.sender])()) { state=states.open;