Kingdom: Time and State

Distributed computation is about time and state. That is, in order for more than one component to communicate, state must be shared, and all that takes time.

Most programmers anthropomorphize their work. They think about one thread of control carrying out the entire program in the same way they would if they had to do the job themselves. Modern computers, however, switch between tasks very quickly, and in multi-core, multi-CPU, or distributed systems, two events may take place at exactly the same time. Defects rush to fill the gap between the programmer's model of how a program executes and what happens in reality. These defects are related to unexpected interactions between threads, processes, time, and information. These interactions happen through shared state: semaphores, variables, the file system, and, basically, anything that can store information.

Often Misused: Block Values

Abstract
A function uses either block.timestamp or block.number as a proxy for time.
Explanation
Values associated with block.timestamp or block.number are often used by developers to trigger time-dependent events, however, these values often give a sense of time that is generally not safe to use.

Due to the decentralized nature of blockchain, nodes can synchronize time only to a certain degree. Using block.timestamp is unreliable at best, and at worst, malicious miners can alter the timestamp of their blocks if they see an advantage to do so.

As for block.number, even though it is possible to predict the time between blocks (approximately 14 seconds), block times are not constant and can vary depending on network activity. This makes block.number unreliable for time-related calculations.

Example 1: The following code uses block.number to unlock funds after a certain period of time.


function withdraw() public {
require(users[msg.sender].amount > 0, 'no amount locked');
require(block.number >= users[msg.sender].unlockBlock, 'lock period not over');
uint amount = users[msg.sender].amount;
users[msg.sender].amount = 0;
(bool success, ) = msg.sender.call.value(amount)("");
require(success, 'transfer failed');
}
References
[1] Enterprise Ethereum Alliance Don't misuse block data
[2] Standards Mapping - Smart Contract Weakness Classification SWC-116
desc.structural.solidity.swc116