The book is intended to serve both as a reference manual and as a cover-to-coverexploration of Ethereum. The first two chapters offer a gentle introduction, suitablefor novice users, and the examples in those chapters can be completed by anyonexiiiwww.EBooksWorld.irwith a bit of technical skill. Those two chapters will give you a good grasp of thebasics and allow you to use the fundamental tools of Ethereum. Chapter 3 andbeyond are intended mainly for programmers and include many technical topics andprogramming examples.To serve as both a reference manual and a cover-to-cover narrative about Ethereum,the book inevitably contains some duplication. Some topics, such as gas, have to beintroduced early enough for the rest of the topics to make sense, but are also exam‐ined in depth in their own sections.Finally, the book’s index allows readers to find very specific topics and the relevantsections with ease, by keyword
Adding numbers larger than the data types range is called an overflow. For clarity, adding 257 to a uint8 that currently has a value of 0 will result in the number 1. It is sometimes instructive to think of fixed-size variables as being cyclic, where we start again from zero if we add numbers above the largest possible stored number, and start counting down from the largest number if we subtract from zero. In the case of signed int types, which can represent negative numbers, we start again once we reach the largest negative value; for example, if we try to subtract 1 from a uint8 whose value is -128, we will get 127. Arithmetic Over/Underflows www.EBooksWorld.ir | 177 These kinds of numerical gotchas allow attackers to misuse code and create unexpec ted logic flows. For example, consider the TimeLock contract in Example 9-3.
id: fe7d26507fe9f3dbab8d7cfc51b55689 - page: 215
Example 9-3. TimeLock.sol 1 contract TimeLock { 2 3 mapping(address => uint) public balances; 4 mapping(address => uint) public lockTime; 5 6 function deposit() public payable { 7 balances[msg.sender] += msg.value; 8 lockTime[msg.sender] = now + 1 weeks; 9 } 10 11 function increaseLockTime(uint _secondsToIncrease) public { 12 lockTime[msg.sender] += _secondsToIncrease; 13 } 14 15 function withdraw() public { 16 require(balances[msg.sender] > 0); 17 require(now > lockTime[msg.sender]); 18 balances[msg.sender] = 0; 19 msg.sender.transfer(balance); 20 } 21 } This contract is designed to act like a time vault: users can deposit ether into the con tract and it will be locked there for at least a week. The user may extend the wait time to longer than 1 week if they choose, but once deposited, the user can be sure their ether is locked in safely for at least a weekor so this contract intends.
id: a414d9fdf6a57b365af30c63417bbf7f - page: 216
In the event that a user is forced to hand over their private key, a contract such as this might be handy to ensure their ether is unobtainable for a short period of time. But if a user had locked in 100 ether in this contract and handed their keys over to an attacker, the attacker could use an overflow to receive the ether, regardless of the lock Time. The attacker could determine the current lockTime for the address they now hold the key for (its a public variable). Lets call this userLockTime. They could then call the increaseLockTime function and pass as an argument the number 2^256 userLock Time. This number would be added to the current userLockTime and cause an over flow, resetting lockTime[msg.sender] to 0. The attacker could then simply call the withdraw function to obtain their reward. Lets look at another example (Example 9-4), this one from the Ethernaut challenges. 178 | Chapter 9: Smart Contract Security
id: e41671b1acb41d62b3aa9c6723ad1a7c - page: 216
EBooksWorld.ir SPOILER ALERT: If you have not yet done the Ethernaut challenges, this gives a solu tion to one of the levels. Example 9-4. Underflow vulnerability example from Ethernaut challenge 1 pragma solidity ^0.4.18; 2 3 contract Token { 4 5 mapping(address => uint) balances; 6 uint public totalSupply; 7 8 function Token(uint _initialSupply) { 9 balances[msg.sender] = totalSupply = _initialSupply; 10 } 11 12 function transfer(address _to, uint _value) public returns (bool) { 13 require(balances[msg.sender] _value >= 0); 14 balances[msg.sender] -= _value; 15 balances[_to] += _value; 16 return true; 17 } 18 19 function balanceOf(address _owner) public constant returns (uint balance) { 20 return balances[_owner]; 21 } 22 } This is a simple token contract that employs a transfer function, allowing partici pants to move their tokens around. Can you see the error in this contract?
id: 5f6b8ca60390b2b318567a8f7f1c3a08 - page: 216