bin2chen

Posted on

# Ethernaut系列-Level 13(GatekeeperOne)

## LEVEL 13 （GatekeeperOne）:

pragma solidity ^0.6.0;

import '@openzeppelin/contracts/math/SafeMath.sol';

contract GatekeeperOne {

using SafeMath for uint256;

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

modifier gateTwo() {
require(gasleft().mod(8191) == 0);
_;
}

modifier gateThree(bytes8 _gateKey) {
require(uint32(uint64(_gateKey)) == uint16(uint64(_gateKey)), "GatekeeperOne: invalid gateThree part one");
require(uint32(uint64(_gateKey)) != uint64(_gateKey), "GatekeeperOne: invalid gateThree part two");
require(uint32(uint64(_gateKey)) == uint16(tx.origin), "GatekeeperOne: invalid gateThree part three");
_;
}

function enter(bytes8 _gateKey) public gateOne gateTwo gateThree(_gateKey) returns (bool) {
entrant = tx.origin;
return true;
}
}

entrant=player

## 要点

1.tx.origin和msg.sender的区别，这个前面有讲
2.gas费用的设置
https://docs.soliditylang.org/en/v0.8.14/control-structures.html?highlight=gas%3A#external-function-calls
3.类型转换和位值
https://docs.soliditylang.org/en/v0.8.14/types.html#conversions-between-elementary-types

## 解题思路

gateOne:在自己的合约调用其他合约，则tx.origin和msg.sender就会不一样

gateTwo:要先了解下gasleft()和合约是如何消耗gas,如何指定调用的最大gas

gateThree:

contracts/13GatekeeperOneRun.sol

//gas = 254+8191; (用console.log打印出gas剩余,本地测算是254，不过线上可能有些许差异可能是有带优化参数,所以可以调小254进行循环测试)
uint256 gas = 254+81910;

/**
*
*  1.require(uint32(uint64(_gateKey)) == uint16(uint64(_gateKey)), "GatekeeperOne: invalid gateThree part one");
*  2.require(uint32(uint64(_gateKey)) != uint64(_gateKey), "GatekeeperOne: invalid gateThree part two");
*  3.require(uint32(uint64(_gateKey)) == uint16(tx.origin), "GatekeeperOne: invalid gateThree part three");
*  gateKey三个条件都满足才能通过
*  分析：
*  根据条件3：tx.origin的0-16跟gateKey的0-16是一样
*  根据条件1：16-32位要全是0 （不然截取后不会相等）
*  根据条件2：32-64位不全是0  (不然截取后会相等)