Ethernaut 题库闯关 第 3 关题解。
今天这篇是Ethernaut 题库闯关连载的第3篇,难度等级:中等。
今天需要 Hack 一个投掷硬币(CoinFlip)的游戏合约,要求连续10次猜出投掷硬币正确的结果。
以下是投掷硬币(CoinFlip)的源代码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import '@openzeppelin/contracts/math/SafeMath.sol';
contract CoinFlip {
using SafeMath for uint256;
uint256 public consecutiveWins;
uint256 lastHash;
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
constructor() public {
consecutiveWins = 0;
}
function flip(bool _guess) public returns (bool) {
uint256 blockValue = uint256(blockhash(block.number.sub(1)));
if (lastHash == blockValue) {
revert();
}
lastHash = blockValue;
uint256 coinFlip = blockValue.div(FACTOR);
bool side = coinFlip == 1 ? true : false;
if (side == _guess) {
consecutiveWins++;
return true;
} else {
consecutiveWins = 0;
return false;
}
}
}
我们需要通过调用flip()
函数传递正确的猜测,实现连续猜出硬币的翻转结果。
在查看解题思路之前,可以先自己想一想,自己会怎么做。
首先我们注意到,所使用的Solidity编译器版本是< 0.8.x
。这意味着该合约很容易出现数学下溢和溢出的错误。
这个合约导入并使用了OpenZeppelin SafeMath库,因此他们应该没有溢出问题。
合约有三个状态变量:
consecutiveWins
在constructor
中被初始化为0。这个变量将保存我们连续猜对了多少次。FACTOR
,被声明为57896044618658097711785492504343953926634992332820282019728792003956564819968
。Gas优化提示:可以声明为constant
以节省Gas(见进一步阅读)。lastHash
,将由flip()
函数每次更新。合约中唯一的函数是flip()
,让我们看看它的作用:
function flip(bool _guess) public returns (bool) {
uint256 blockValue = uint256(blockhash(block.number.sub(1)));
if (lastHash =...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!