[Ethernaut CTF] Elevator

0xDave·2022년 10월 4일
0

Ethereum

목록 보기
32/112

소스코드


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

interface Building {
  function isLastFloor(uint) external returns (bool);
}


contract Elevator {
  bool public top;
  uint public floor;

  function goTo(uint _floor) public {
    Building building = Building(msg.sender);

    if (! building.isLastFloor(_floor)) {
      floor = _floor;
      top = building.isLastFloor(floor);
    }
  }
}

해결과제


This elevator won't let you reach the top of your building. Right?
Things that might help:

    Sometimes solidity is not good at keeping promises.
    This Elevator expects to be used from a Building.

해결과정


꼭대기 층에 가면 될 것 같지만 어디까지가 끝인지 모른다. Top에 true 값을 주면 되지 않을까?

Interface

한 동안 골머리를 앓다가 답을 봐도 이해가 안 됐었다. 먼저 인터페이스에 대한 이해가 필요하다. 인터페이스를 설명할 때 자주 드는 예는 자동차의 브레이크다. 운전할 때 운전자는 브레이크가 어떻게 설계됐는지 알 필요가 없이 그냥 밟기만 하면 된다. 운전자가 알아야 할 것은 브레이크를 밟으면 자동차가 멈춘다는 것이다.

이와 같이 컨트랙트에 있는 함수를 다른 컨트랙트에서 사용하고자 할 때 인터페이스를 사용할 수 있는데, 예를 들어 컨트랙트A에 있는 함수A'를 컨트랙트B에서 사용하고자 할 때 사용자는 함수A'가 어떤 메커니즘으로 설계돼있는지 알 필요가 없다. 그저 인터페이스에서 호출하면 함수A'가 동작한다는 것만 알면 된다. 이 때 컨트랙트A의 주소가 필요하다.

의문점

Building building = Building(msg.sender);

인터페이스를 사용할 때 보통 컨트랙트의 주소를 넣는다. 그런데 여기에는 msg.sender를 인자로 받는다. 인터페이스를 사용할 때 컨트랙트의 주소가 반드시 필요한 게 아닌걸까. 해답과 관련된 의문은 아니지만 왜 이렇게 설계했는지, 어떻게 동작하는지 궁금했다. stack overflow에 질문해봤지만 아직까지 명쾌하게 이해되지 않았다. 이해되는대로 글로 남길 예정이다.

해답

의문은 아직 풀리지 않았지만 문제에 대한 해답은 인터페이스에 선언된 상태에 있었다. view 또는 pure로 선언되지 않은 인터페이스는 상태를 변환시킬 수 있다. 핵심은 isLastFloor() 함수가 두 번째 호출될 때 boolean이 바뀌도록 하는 것이다. 이렇게 되면 처음 false였던 상태로 goTo 함수가 실행되고 if문이 실행된다. floor 값을 전달한 뒤 다시 한 번 isLastFloor() 함수가 호출되면 top 값에는 true가 할당되면서 문제가 풀린다.

여기서 얻을 수 있는 교훈은 interface로 선언된 함수의 값을 고정시키고 싶을 때 반드시 view 또는 pure를 사용해야 한다는 것이다.

profile
Just BUIDL :)

0개의 댓글