1. 문제

초능력을 사용하여 10번 연속으로 정답을 맞춰라
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;
        }
    }
}

2. block 개념

Attack이라는 이름의 컨트랙트의 attack 함수를 호출하면 코인 뒤집기 결과를 계산하여 함수 내부에서 CoinFlip 컨트랙트의 flip 함수를 호출한다고 가정하자

image.png

이렇게 호출된 함수는 하나의 Transaction에 담기게 되고

image.png

이 Transaction은 하나의 Block에 담기게 된다

image.png

하나의 블록 안에있는 트랜잭션에서 함수 호출이 처리되었다는 것은 곧 attack 함수에서 불러온 block.number와 flip 함수에서 불러온 block.number의 값이 동일하다는 것을 의미한다.

image.png

즉, 이를 이용하면 CoinFlip의 block.number와 같은 block.number를 추출하고 이를 활용할 수 있게된다.