Think Solidity with Sense of Security
Never show secret on chain
Remember always show the hashed secret on chain!
This code is secure because commit is stored in hash instead of plaintext.
1 | bytes32 public commit; |
Let’s take a look at the insecure code ⚠️.
Attackers can monitor the mempool to obtain the plaintext secret, allowing them to front-run the transaction in the same block or a subsequent block.
1 | contract BadCommit { |
Generate random value in Solidity?
Intro
Using on-chain variables like blockhash/block.timestamp as a source of randomness is
insecure, because an attacker could synchronously compute the same result on-chain with the same input.
To understand this, try to do the flip coin game on https://ethernaut.openzeppelin.com/level/0xA62fE5344FE62AdC1F356447B669E9E6D10abaaF
When this contract is deployed, for example, the deployment address is: 0x0ff691A7e70ae5b7f4eBeE176959f775b7E9Fa6f.
Use the following code to attack the smart contract:
1 |
|
Key point: when you call attack(), both your attack contract and the target contract are executed within the same block context (i.e., the same transaction execution environment).
- block.number has the same value for both contracts
- blockhash(block.number - 1) therefore resolves to the same hash
As a result, the side value you compute is guaranteed to be identical to the value computed internally by the target contract. It is deterministically computing the same result at the same time.
The reason for not having a natural random value in Solidity is that the Blockchain is a deterministic system. All nodes must calculate the same output. Otherwise, the chain would be forked, consensus would collapse!
There are 3 ways for random value is recognised in the Solidity world:
- Chainlink VRF (Verifiable Random Function)
- Commit-Reveal
- Multi-party Randomness
Be extremely careful with overflow!
Check this question first: https://ethernaut.openzeppelin.com/level/0x478f3476358Eb166Cb7adE4666d04fbdDB56C407
Before Solidity 8.0, there was no auto-check for unsigned integers, so overflow happened. In this case, if I make the transfer value equal to 21. 20-21=2^256-1 (horrible number!!!!).
As a result, SafeMath lib is used before the version of Solidity 8.0. Example code:
1 | using SafeMath for uint256; |
