Серия «Этернаут» — уровень 14 (GatekeeperTwo)


УРОВЕНЬ 14 (ПривратникДва):

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract GatekeeperTwo {

  address public entrant;

  modifier gateOne() {
    require(msg.sender != tx.origin);
    _;
  }

  modifier gateTwo() {
    uint x;
    assembly { x := extcodesize(caller()) }
    require(x == 0);
    _;
  }

  modifier gateThree(bytes8 _gateKey) {
    require(uint64(bytes8(keccak256(abi.encodePacked(msg.sender)))) ^ uint64(_gateKey) == uint64(0) - 1);
    _;
  }

  function enter(bytes8 _gateKey) public gateOne gateTwo gateThree(_gateKey) returns (bool) {
    entrant = tx.origin;
    return true;
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Требования

абитуриент=игрок

Ключевые моменты

1. разница между tx.origin и msg.sender, которая обсуждалась ранее
2. разница между EOA и контрактом, а также extcodesize
3. Расчет битов
^ Изо-или Два бита одинаковы для 0, различны для 1

Идеи решения проблем

gateOne: если вы вызываете другой контракт в своем собственном контракте, tx.origin и msg.sender будут разными
gateTwo: нормальный счет EOA codesize=0, контракт не равен 0, но есть исключение в конструкторе контрактов для подстановки внешних контрактов, когда codesize равен 0, потому что контракт не был инициализирован.
gateThree: вычисление битов, см. следующую подсказку кода

        //gateThree:require(uint64(bytes8(keccak256(abi.encodePacked(msg.sender)))) ^ uint64(_gateKey) == uint64(0) - 1);
        //结果再异或下
        uint64 gateKey;
        unchecked {
            gateKey = (uint64(0) - 1) ^
                uint64(bytes8(keccak256(abi.encodePacked(address(this))))); 
        }
        ILevel(_runAddress).enter(bytes8(gateKey));
    }
Войдите в полноэкранный режим Выход из полноэкранного режима

Оцените статью
Procodings.ru
Добавить комментарий