// 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;
}
}
}
This is a coin flipping game where you need to build up your winning streak by guessing the outcome of a coin flip. To complete this level you'll need to use your psychic abilities to guess the correct outcome 10 times in a row.
Things that might help
See the Help page above, section "Beyond the console"
10번 연속으로 동전의 앞뒷면을 맞추면 된다.
먼저 sub(A, B)
함수는 A에서 B를 뺀 결과를 리턴한다. 그런데 인자로 하나만 넣어주면 앞의 종속된 숫자에서 인자를 뺀 결과를 리턴한다. 즉 block.number.sub(1)
는 현재 블록넘버에서 1을 뺀 결과를 리턴해주는 것.
블록넘버가 지나기 전에 외부 컨트랙트에서 반복문 10번 돌려서 맞추면 되지 않을까?라는 생각에 바로 리믹스를 켰다.
디플로이까지 완료 후 gotcha()
함수를 실행시켰는데 revert가 났다. 아무래도 아래 코드 때문에 그런 것 같다. blockValue 값이 같은 상태에서 10번을 반복하는 것은 안 좋은 방법인 듯.
if (lastHash == blockValue) {
revert();
}
똑같은 코드로 복사해서 필요한 로직만 남겼다. 이전에 디플로이된 CoinFlip 컨트랙트 주소를 가져와서 새로운 인스턴스를 만들고 같은 로직으로 나온 side
를 flip 함수에 넣어주는 방식이다.
계속 gotcha()
함수를 호출하면 contract.consecutiveWins
의 숫자가 올라간다. 시간이 좀 걸리긴 하지만 10번까지 완료하면 끝. 이번 예제를 통해서 랜덤소스를 block.number 또는 blockhash와 같이 모두가 접근 가능한 요소로 정하면 안된다는 것을 다시 한 번 깨달았다. 괜히 체인링크의 vrf를 사용하는 게 아니다. 모두가 접근 가능하다면 이렇게 로직을 베껴서 결과물을 도출할 수 있다. vrf 애용하자.